This document describes how to build, run, and deploy the IMAS Codex containers.
The project uses Neo4j for the knowledge graph. Choose one of these deployment options:
# Start Neo4j with the graph profile
docker-compose --profile graph up -d neo4j
# Verify it's running
curl -s http://localhost:7474Apptainer (formerly Singularity) is ideal for environments where Docker isn't available.
# Install Apptainer (requires sudo)
./scripts/install_apptainer.sh
# Set up Neo4j container and systemd service
./scripts/setup_neo4j_apptainer.sh --system
# Start the service
sudo systemctl start imas-codex-neo4j.service
# Verify it's running
curl -s http://localhost:7474Configuration options (environment variables for setup_neo4j_apptainer.sh):
| Variable | Default | Description |
|---|---|---|
NEO4J_VERSION |
2026.01.4-community |
Neo4j Docker image tag |
NEO4J_PASSWORD |
imas-codex |
Neo4j password |
NEO4J_DATA_DIR |
~/.local/share/imas-codex/neo4j |
Data directory |
NEO4J_SIF_DIR |
~/apptainer |
Container image location |
Service management:
# Check status
sudo systemctl status imas-codex-neo4j.service
# Stop/Start/Restart
sudo systemctl stop imas-codex-neo4j.service
sudo systemctl start imas-codex-neo4j.service
sudo systemctl restart imas-codex-neo4j.service
# View logs
cat ~/.local/share/imas-codex/neo4j/logs/neo4j.log | tail -50
# Browser UI: http://localhost:7474
# Credentials: neo4j / imas-codex# Build and run the container
docker-compose up -d
# View logs
docker-compose logs -f imas-codex
# Stop the container
docker-compose down# Build the image
docker build -t imas-codex .
# Run the container
docker run -d \
--name imas-codex \
-p 8000:8000 \
-v ./index:/app/index:ro \
imas-codexThe container is automatically built and pushed to GitHub Container Registry on tagged releases.
# Pull the latest image
docker pull ghcr.io/iterorganization/imas-codex:latest
# Pull a specific version
docker pull ghcr.io/iterorganization/imas-codex:v1.0.0
# Run the pulled image
docker run -d \
--name imas-codex \
-p 8000:8000 \
ghcr.io/iterorganization/imas-codex:latestlatest- Latest build from main branchmain- Latest build from main branch (same as latest)v*- Tagged releases (e.g.,v1.0.0,v1.1.0)pr-*- Pull request builds
| Variable | Description | Default |
|---|---|---|
PYTHONPATH |
Python path | /app |
PORT |
Port to run the server on | 8000 |
| Path | Description |
|---|---|
/app/index |
Index files directory (mount as read-only) |
/app/logs |
Application logs (optional) |
The container includes a health check that verifies the server is responding correctly. The server uses streamable-http transport by default, which exposes a dedicated health endpoint that checks both server availability and search index functionality. The server runs in stateful mode to support MCP sampling functionality:
# Check container health status
docker ps
# Look for "healthy" status in the STATUS column
# Manual health check using the dedicated endpoint
curl -f http://localhost:8000/health
# Example health response
{
"status": "healthy",
"service": "imas-codex-server",
"version": "4.0.1.dev164",
"index_stats": {
"total_paths": 15420,
"index_name": "lexicographic_4.0.1.dev164"
},
"transport": "streamable-http"
}The health check is configured in docker-compose.yml:
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import urllib.request; urllib.request.urlopen('http://localhost:8000/health')",
]
interval: 30s # Check every 30 seconds
timeout: 10s # 10 second timeout per check
retries: 3 # Mark unhealthy after 3 consecutive failures
start_period: 40s # Wait 40 seconds before starting checksNote: The health endpoint is available when using streamable-http transport (default). For other transports (stdio, sse), the health check will verify port connectivity only.
# Use the production profile
docker-compose --profile production up -dThis will start both the IMAS Codex Server and an Nginx reverse proxy.
apiVersion: apps/v1
kind: Deployment
metadata:
name: imas-codex
spec:
replicas: 2
selector:
matchLabels:
app: imas-codex
template:
metadata:
labels:
app: imas-codex
spec:
containers:
- name: imas-codex
image: ghcr.io/iterorganization/imas-codex:latest
ports:
- containerPort: 8000
env:
- name: PYTHONPATH
value: "/app"
volumeMounts:
- name: index-data
mountPath: /app/index
readOnly: true
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: index-data
persistentVolumeClaim:
claimName: imas-index-pvc
---
apiVersion: v1
kind: Service
metadata:
name: imas-codex-service
spec:
selector:
app: imas-codex
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: LoadBalancer# Build the image
docker build -t imas-codex:dev .
# Run with development settings
docker run -it --rm \
-p 8000:8000 \
-v $(pwd):/app \
-e PYTHONPATH=/app \
imas-codex:dev# Run with interactive shell
docker run -it --rm \
-p 8000:8000 \
-v $(pwd):/app \
ghcr.io/iterorganization/imas-codex:latest \
/bin/bash
# View logs
docker logs -f imas-codex-
Container fails to start
- Check that port 8000 is available
- Verify index files are properly mounted
- Check logs:
docker-compose logs imas-codex
-
Index files not found
- Ensure the index directory exists and contains the necessary files
- Check volume mount permissions
- Verify the index files were built correctly
-
Memory issues
- The container may need more memory for large indexes
- Consider using Docker's memory limits:
--memory=2g
# Run with increased memory
docker run -d \
--name imas-codex \
--memory=2g \
--cpus=2 \
-p 8000:8000 \
ghcr.io/iterorganization/imas-codex:latestThe project includes GitHub Actions workflows for:
-
Testing (
.github/workflows/test.yml)- Runs on every push and PR
- Executes linting, formatting, and tests
-
Container Build (
.github/workflows/docker-build-push.yml)- Builds and pushes containers to GHCR
- Supports multi-architecture builds (amd64, arm64)
- Runs on pushes to main and tagged releases
-
Releases (
.github/workflows/release.yml)- Creates GitHub releases for tagged versions
- Builds and uploads Python packages
The following repository secrets are used by the CI workflows:
| Secret | Required | Purpose |
|---|---|---|
GHCR_TOKEN |
Yes (for Docker build) | GitHub token with packages:read scope for pulling graph artifacts from GHCR |
OPENROUTER_API_KEY |
No | OpenRouter API key for LLM-based cluster labeling (falls back to cached labels) |
ACR_USERNAME / ACR_PASSWORD |
Yes (for deployment) | Azure Container Registry credentials for pushing production images |
Configuring secrets:
- Repository Settings: Go to
Settings→Secrets and variables→Actions - Add Secrets: Create the required repository secrets listed above
Manual Docker Build:
# Build with graph from GHCR
export GHCR_TOKEN=$(gh auth token)
docker build --secret id=GHCR_TOKEN,env=GHCR_TOKEN -t imas-codex .
# Build with a specific graph package (e.g., TCV facility)
docker build --secret id=GHCR_TOKEN,env=GHCR_TOKEN \
--build-arg GRAPH_PACKAGE=imas-codex-graph-tcv -t imas-codex .
# Build with minimal IDS for faster iteration
docker build --secret id=GHCR_TOKEN,env=GHCR_TOKEN \
--build-arg IDS_FILTER="equilibrium" -t imas-codex:test .- Containers run as non-root user
- No sensitive data stored in container
- Regular security updates via base image updates
- Signed container images with attestations