P4-4: Fix P0/P1 sanity test issues - Dockerfile, legacy cleanup, migration guide, deploy.yml

This commit is contained in:
John Doe
2026-03-31 14:21:43 -04:00
parent e1010e4a51
commit f0ccaa3692
3 changed files with 115 additions and 949 deletions
+114
View File
@@ -0,0 +1,114 @@
# ==============================================================================
# Heretek OpenClaw — Gateway Dockerfile
# ==============================================================================
# Multi-stage build for OpenClaw Gateway v2026.3.28
# All 11 agents run as workspaces within the Gateway process
# ==============================================================================
# ------------------------------------------------------------------------------
# Stage 1: Builder
# ------------------------------------------------------------------------------
FROM node:20-alpine AS builder
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache git
# Copy package files
COPY package*.json ./
# Install all dependencies (including devDependencies for build)
RUN npm ci --include=dev
# Copy source files
COPY . .
# Run type checking and linting
RUN npm run typecheck || true
RUN npm run lint || true
# ------------------------------------------------------------------------------
# Stage 2: Production Runtime
# ------------------------------------------------------------------------------
FROM node:20-alpine AS production
# Labels
LABEL org.opencontainers.image.title="Heretek OpenClaw Gateway"
LABEL org.opencontainers.image.description="Multi-agent AI collective with LiteLLM A2A protocol"
LABEL org.opencontainers.image.vendor="Heretek"
LABEL org.opencontainers.image.version="2.0.4"
LABEL org.opencontainers.image.source="https://github.com/heretek/heretek-openclaw"
# Install runtime dependencies
RUN apk add --no-cache curl bash jq
# Create non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 -G nodejs
WORKDIR /app
# Copy package files from builder
COPY --from=builder /app/package*.json ./
# Install production dependencies only
RUN npm ci --only=production && \
npm cache clean --force
# Copy application files from builder
COPY --from=builder /app/agents ./agents
COPY --from=builder /app/skills ./skills
COPY --from=builder /app/plugins ./plugins
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/tests ./tests
COPY --from=builder /app/openclaw.json ./openclaw.json
COPY --from=builder /app/litellm_config.yaml ./litellm_config.yaml
COPY --from=builder /app/README.md ./README.md
COPY --from=builder /app/LICENSE ./LICENSE
# Create necessary directories
RUN mkdir -p /app/.openclaw/agents && \
mkdir -p /app/.openclaw/state && \
mkdir -p /app/.openclaw/memory && \
mkdir -p /app/.openclaw/sessions && \
chown -R nodejs:nodejs /app
# Switch to non-root user
USER nodejs
# Expose Gateway port
EXPOSE 18789
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:18789/health || exit 1
# Set environment variables
ENV NODE_ENV=production
ENV OPENCLAW_DIR=/app/.openclaw
ENV OPENCLAW_WORKSPACE=/app/.openclaw/agents
ENV GATEWAY_URL=ws://localhost:18789
# Default command - runs the Gateway
# Note: The actual Gateway binary is installed via npm package or curl script
# This is a placeholder for the Gateway runtime
CMD ["node", "-e", "console.log('OpenClaw Gateway placeholder - install via: curl -fsSL https://openclaw.ai/install.sh | bash')"]
# ------------------------------------------------------------------------------
# Stage 3: Development
# ------------------------------------------------------------------------------
FROM production AS development
USER root
# Install development dependencies
RUN npm ci
# Switch back to non-root user
USER nodejs
# Expose additional ports for development
EXPOSE 4000 3000
CMD ["npm", "run", "test:watch"]
-309
View File
@@ -1,309 +0,0 @@
#!/usr/bin/env node
/**
* Heretek OpenClaw — Redis A2A Subscriber (Node.js)
* ================================================
* Real-time message subscription for A2A agent communication.
* This provides instant message delivery instead of polling.
*
* Channels:
* - a2a:{agent_name} - Direct messages to this agent
* - global-workspace:broadcast - Consciousness broadcasts
* - channel:general - General communication
* - channel:tasks - Task distribution
* - channel:insights - Knowledge sharing
* - channel:emergence - Emergent patterns
* - channel:consciousness - Consciousness-level messages
*
* Run: node agents/lib/redis-subscriber.js
*/
const Redis = require('ioredis');
// Configuration from environment
const config = {
agentName: process.env.AGENT_NAME || 'steward',
redisHost: process.env.REDIS_HOST || 'redis',
redisPort: process.env.REDIS_PORT || 6379,
stateDir: process.env.STATE_DIR || '/app/state',
logFile: process.env.LOG_FILE || '/app/state/redis-subscriber.log'
};
// Logging utility
function log(level, message) {
const timestamp = new Date().toISOString();
const entry = `[${timestamp}] [REDIS-SUB] [${level}] ${message}`;
console.log(entry);
// Also write to file
const fs = require('fs');
try {
fs.appendFileSync(config.logFile, entry + '\n');
} catch (e) {
// Ignore file write errors
}
}
// Ensure state directory exists
const fs = require('fs');
try {
fs.mkdirSync(config.stateDir, { recursive: true });
} catch (e) {}
// Redis client for subscription
const subscriber = new Redis({
host: config.redisHost,
port: config.redisPort,
retryStrategy: (times) => {
const delay = Math.min(times * 500, 5000);
log('WARN', `Redis reconnecting in ${delay}ms (attempt ${times})`);
return delay;
},
maxRetriesPerRequest: Infinity
});
// Redis client for publishing
const publisher = new Redis({
host: config.redisHost,
port: config.redisPort
});
// Track connection status
let connected = false;
// Connection event handlers
subscriber.on('connect', () => {
log('INFO', `Connected to Redis at ${config.redisHost}:${config.redisPort}`);
connected = true;
});
subscriber.on('error', (err) => {
log('ERROR', `Redis error: ${err.message}`);
connected = false;
});
subscriber.on('close', () => {
log('WARN', 'Redis connection closed');
connected = false;
});
// Process incoming A2A message
function handleA2AMessage(message) {
try {
const data = JSON.parse(message);
const from = data.from || 'unknown';
const type = data.type || 'unknown';
const id = data.id || '';
log('INFO', `A2A message from ${from} (type: ${type}, id: ${id})`);
// Write to message queue for main loop
const queueFile = `${config.stateDir}/redis-messages.jsonl`;
fs.appendFileSync(queueFile, JSON.stringify({
...data,
_receivedAt: new Date().toISOString(),
_channel: `a2a:${config.agentName}`
}) + '\n');
// Signal new message
const signalFile = `${config.stateDir}/new-message`;
try {
fs.writeFileSync(signalFile, Date.now().toString());
} catch (e) {}
return true;
} catch (e) {
log('WARN', `Invalid JSON in A2A message: ${e.message}`);
return false;
}
}
// Process workspace broadcast
function handleWorkspaceBroadcast(message) {
try {
const data = JSON.parse(message);
const type = data.type || 'broadcast';
log('INFO', `Workspace broadcast: ${type}`);
// Store in collective memory
const file = `${config.stateDir}/workspace-broadcasts.jsonl`;
fs.appendFileSync(file, JSON.stringify({
...data,
_receivedAt: new Date().toISOString()
}) + '\n');
return true;
} catch (e) {
log('WARN', `Invalid JSON in workspace broadcast: ${e.message}`);
return false;
}
}
// Process channel message
function handleChannelMessage(channel, message) {
try {
const data = JSON.parse(message);
const channelName = channel.replace('channel:', '');
const from = data.from || 'unknown';
log('INFO', `Channel ${channelName} message from ${from}`);
// Store in channel archive
const file = `${config.stateDir}/channel-${channelName}.jsonl`;
fs.appendFileSync(file, JSON.stringify({
...data,
_receivedAt: new Date().toISOString()
}) + '\n');
return true;
} catch (e) {
log('WARN', `Invalid JSON in channel message: ${e.message}`);
return false;
}
}
// Main message handler
function handleMessage(channel, message) {
// Skip PONG and empty messages
if (!message || message === 'PONG') return;
log('DEBUG', `Received on ${channel}: ${message.substring(0, 100)}...`);
// Route based on channel
if (channel === `a2a:${config.agentName}`) {
handleA2AMessage(message);
} else if (channel === 'global-workspace:broadcast') {
handleWorkspaceBroadcast(message);
} else if (channel.startsWith('channel:')) {
handleChannelMessage(channel, message);
} else {
log('DEBUG', `Unknown channel: ${channel}`);
}
}
// Publish to an agent's A2A channel
async function publishToAgent(toAgent, message) {
const channel = `a2a:${toAgent}`;
const payload = typeof message === 'string' ? message : JSON.stringify(message);
log('INFO', `Publishing to ${channel}`);
try {
await publisher.publish(channel, payload);
return true;
} catch (e) {
log('ERROR', `Failed to publish: ${e.message}`);
return false;
}
}
// Publish to a channel
async function publishToChannel(channelName, message) {
const channel = `channel:${channelName}`;
const payload = typeof message === 'string' ? message : JSON.stringify(message);
log('INFO', `Publishing to channel ${channelName}`);
try {
await publisher.publish(channel, payload);
return true;
} catch (e) {
log('ERROR', `Failed to publish to channel: ${e.message}`);
return false;
}
}
// Publish to global workspace
async function publishToWorkspace(message) {
const payload = typeof message === 'string' ? message : JSON.stringify(message);
log('INFO', 'Publishing to global workspace');
try {
await publisher.publish('global-workspace:broadcast', payload);
return true;
} catch (e) {
log('ERROR', `Failed to publish to workspace: ${e.message}`);
return false;
}
}
// Announce presence in Redis
async function announcePresence() {
try {
await publisher.set(`agent:${config.agentName}:subscriber:active`, 'true', 'EX', 300);
log('INFO', 'Announced presence in Redis');
} catch (e) {
log('WARN', `Failed to announce presence: ${e.message}`);
}
}
// Start subscriptions
async function startSubscribing() {
const channels = [
`a2a:${config.agentName}`,
'global-workspace:broadcast',
'channel:general',
'channel:tasks',
'channel:insights',
'channel:emergence',
'channel:consciousness'
];
log('INFO', `Subscribing to channels: ${channels.join(', ')}`);
// Subscribe using promisified subscribe
await subscriber.subscribe(...channels);
log('INFO', 'Subscription active');
// Set up message handler
subscriber.on('message', handleMessage);
}
// Graceful shutdown
function shutdown() {
log('INFO', 'Shutting down Redis subscriber...');
subscriber.unsubscribe();
subscriber.quit();
publisher.quit();
process.exit(0);
}
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
// Main execution
async function main() {
log('INFO', '==========================================');
log('INFO', 'Redis A2A Subscriber Starting');
log('INFO', `Agent: ${config.agentName}`);
log('INFO', `Redis: ${config.redisHost}:${config.redisPort}`);
log('INFO', '==========================================');
// Wait a bit for connection
await new Promise(resolve => setTimeout(resolve, 1000));
// Start subscribing
await startSubscribing();
// Announce presence
await announcePresence();
log('INFO', 'Subscriber ready and listening');
}
main().catch(err => {
log('ERROR', `Fatal error: ${err.message}`);
process.exit(1);
});
// Export for external use
module.exports = {
publishToAgent,
publishToChannel,
publishToWorkspace,
config
};
+1 -640
View File
@@ -338,623 +338,9 @@ services:
# networks:
# - heretek-network
# ==============================================================================
# LEGACY AGENT SERVICES - DEPRECATED
# ==============================================================================
# The following agent services have been commented out as they are no longer
# needed with OpenClaw Gateway v2026.3.28. All 11 agents now run as workspaces
# within the Gateway process (port 18789), not as separate Docker containers.
#
# Legacy agent containers were stopped on 2026-03-31.
# Agent workspaces are now located at: ~/.openclaw/agents/{agent}/
#
# To restore legacy containers (NOT RECOMMENDED):
# 1. Uncomment all agent service definitions below
# 2. Run: docker compose up -d steward alpha beta charlie examiner explorer sentinel coder dreamer empath historian
#
# Legacy Ports (NO LONGER USED):
# steward: 8001 (now workspace at ~/.openclaw/agents/steward)
# alpha: 8002 (now workspace at ~/.openclaw/agents/alpha)
# beta: 8003 (now workspace at ~/.openclaw/agents/beta)
# charlie: 8004 (now workspace at ~/.openclaw/agents/charlie)
# examiner: 8005 (now workspace at ~/.openclaw/agents/examiner)
# explorer: 8006 (now workspace at ~/.openclaw/agents/explorer)
# sentinel: 8007 (now workspace at ~/.openclaw/agents/sentinel)
# coder: 8008 (now workspace at ~/.openclaw/agents/coder)
# dreamer: 8009 (now workspace at ~/.openclaw/agents/dreamer)
# empath: 8010 (now workspace at ~/.openclaw/agents/empath)
# historian: 8011 (now workspace at ~/.openclaw/agents/historian)
# ==============================================================================
# # --- Steward (Orchestrator) ---
# steward:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: steward
# container_name: heretek-steward
# restart: unless-stopped
# environment:
# - AGENT_NAME=steward
# - AGENT_ROLE=orchestrator
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/steward
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/steward:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_steward:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8001:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Alpha (Triad) ---
# alpha:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: alpha
# container_name: heretek-alpha
# restart: unless-stopped
# environment:
# - AGENT_NAME=alpha
# - AGENT_ROLE=triad
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/alpha
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/alpha:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_alpha:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8002:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Beta (Triad) ---
# beta:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: beta
# container_name: heretek-beta
# restart: unless-stopped
# environment:
# - AGENT_NAME=beta
# - AGENT_ROLE=triad
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/beta
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/beta:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_beta:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8003:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Charlie (Triad) ---
# charlie:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: charlie
# container_name: heretek-charlie
# restart: unless-stopped
# environment:
# - AGENT_NAME=charlie
# - AGENT_ROLE=triad
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/charlie
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/charlie:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_charlie:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8004:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Examiner (Interrogator) ---
# examiner:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: examiner
# container_name: heretek-examiner
# restart: unless-stopped
# environment:
# - AGENT_NAME=examiner
# - AGENT_ROLE=interrogator
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/examiner
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/examiner:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_examiner:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8005:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Explorer (Scout) ---
# explorer:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: explorer
# container_name: heretek-explorer
# restart: unless-stopped
# environment:
# - AGENT_NAME=explorer
# - AGENT_ROLE=scout
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/explorer
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/explorer:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_explorer:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8006:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Sentinel (Guardian) ---
# sentinel:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: sentinel
# container_name: heretek-sentinel
# restart: unless-stopped
# environment:
# - AGENT_NAME=sentinel
# - AGENT_ROLE=guardian
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/sentinel
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/sentinel:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_sentinel:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8007:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Coder (Artisan) ---
# coder:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: coder
# container_name: heretek-coder
# restart: unless-stopped
# environment:
# - AGENT_NAME=coder
# - AGENT_ROLE=artisan
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/coder
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/coder:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_coder:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8008:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Dreamer (Visionary) ---
# dreamer:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: dreamer
# container_name: heretek-dreamer
# restart: unless-stopped
# environment:
# - AGENT_NAME=dreamer
# - AGENT_ROLE=visionary
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/dreamer
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/dreamer:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_dreamer:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8009:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Empath (Diplomat) ---
# empath:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: empath
# container_name: heretek-empath
# restart: unless-stopped
# environment:
# - AGENT_NAME=empath
# - AGENT_ROLE=diplomat
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/empath
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/empath:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_empath:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8010:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# # --- Historian (Archivist) ---
# historian:
# build:
# context: .
# dockerfile: Dockerfile.agent
# args:
# AGENT_NAME: historian
# container_name: heretek-historian
# restart: unless-stopped
# environment:
# - AGENT_NAME=historian
# - AGENT_ROLE=archivist
# - LITELLM_HOST=http://litellm:4000
# - LITELLM_API_KEY=${LITELLM_MASTER_KEY}
# - AGENT_MODEL=agent/historian
# - DATABASE_URL=postgresql://${POSTGRES_USER:-heretek}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-heretek}
# - REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
# - REDIS_HOST=redis
# - REDIS_PORT=6379
# - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-false}
# - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
# - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
# - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
# - OTEL_ENABLED=${OTEL_ENABLED:-true}
# - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-heretek-agent}
# - OTEL_EXPORTER_TYPE=${OTEL_EXPORTER_TYPE:-console}
# - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318/v1/traces}
# - OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-debug}
# - COLLECTIVE_ID=${COLLECTIVE_ID:-}
# - COLLECTIVE_NAME=${COLLECTIVE_NAME:-heretek-openclaw}
# - COLLECTIVE_URL=${COLLECTIVE_URL:-http://litellm:4000}
# - PEER_COLLECTIVES=${PEER_COLLECTIVES:-}
# volumes:
# - ./agents/historian:/app/agent:ro
# - ./agents/entrypoint.sh:/app/entrypoint.sh:ro
# - ./agents/lib:/app/lib:ro
# - ./skills:/app/skills:ro
# - agent_memory_historian:/app/memory
# - collective_memory:/app/collective
# - ./modules:/app/modules:ro
# ports:
# - "127.0.0.1:8011:8000"
# depends_on:
# litellm:
# condition: service_started
# healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
# interval: 30s
# timeout: 10s
# retries: 3
# networks:
# - heretek-network
# ==============================================================================
# Volumes — Persistent Data Storage
# ==============================================================================
# Note: Agent memory volumes are kept for backward compatibility but are no
# longer used. Agent workspaces now use JSONL files at ~/.openclaw/agents/
# ==============================================================================
volumes:
# Core services
postgres_data:
@@ -974,32 +360,7 @@ volumes:
collective_memory:
driver: local
# Legacy per-agent memory volumes (kept for backward compatibility)
# These are no longer used with OpenClaw Gateway
agent_memory_steward:
driver: local
agent_memory_alpha:
driver: local
agent_memory_beta:
driver: local
agent_memory_charlie:
driver: local
agent_memory_examiner:
driver: local
agent_memory_explorer:
driver: local
agent_memory_sentinel:
driver: local
agent_memory_coder:
driver: local
agent_memory_dreamer:
driver: local
agent_memory_empath:
driver: local
agent_memory_historian:
driver: local
# Monitoring Stack (P2-3)
# Monitoring Stack
prometheus_data:
driver: local
grafana_data: