# Trigger.dev Worker Image with CFN Agent Infrastructure

This document describes the custom trigger.dev worker image that integrates CFN Loop agent execution capabilities.

## Overview

The worker image extends the official trigger.dev base image with:
- CFN agent execution environment (claude-flow-novice CLI)
- Per-agent container spawning capabilities via Docker-in-Docker
- Custom AI provider routing (Z.ai, Kimi, OpenRouter, Anthropic)
- Agent template mounting for dynamic agent loading

## Image Architecture

```
Base: ghcr.io/triggerdotdev/trigger.dev:latest
├── CFN Dependencies
│   ├── claude-flow-novice CLI (global npm install)
│   ├── TypeScript compiler (ts-node)
│   └── Docker CLI (for per-agent containers)
├── Trigger.dev Workflows
│   ├── trigger-dev/src/ (workflow definitions)
│   ├── trigger-dev/package.json (dependencies)
│   └── Built JavaScript (npm run build)
├── Agent Templates
│   └── .claude/agents/ (mounted from host)
└── Deliverables Directory
    └── /tmp/trigger-dev-deliverables (worker output)
```

## Build Process

### Standard Build (Recommended - 96% faster)

Use the docker-build skill for optimal performance on WSL2:

```bash
# From project root
./.claude/skills/docker-build/build.sh \
  --dockerfile docker/trigger-dev/Dockerfile.worker \
  --tag trigger-dev-worker-cfn:latest
```

**Performance Benefits:**
- 96% faster builds vs direct Docker build on Windows mounts
- Automatic context sync to Linux native storage
- BuildKit optimization enabled
- Prevents OOM errors (exit code 137)

### Manual Build (Alternative)

```bash
# Direct Docker build (slower on WSL2)
docker build -f docker/trigger-dev/Dockerfile.worker \
  -t trigger-dev-worker-cfn:latest .
```

**Note:** Manual builds on WSL2 Windows mounts may take 755s vs <20s with Linux native storage.

## Environment Configuration

### Required Environment Variables

```bash
# Trigger.dev Configuration
TRIGGER_API_KEY=tr_dev_...              # API authentication
TRIGGER_API_URL=http://trigger-webapp:3000  # Webapp endpoint
WORKER_MODE=true                         # Enable worker mode
WORKER_ID=trigger-worker-1               # Unique worker identifier

# Database and Services
DATABASE_URL=postgresql://...            # PostgreSQL connection
REDIS_URL=redis://redis:6379             # Redis for job queue
MINIO_URL=http://minio:9000              # Object storage
CLICKHOUSE_URL=http://clickhouse:8123    # Analytics database

# CFN Agent Execution
ANTHROPIC_API_KEY=sk-ant-...             # Claude API key (required)
CFN_WORKSPACE=/workspace                 # Agent workspace path
CFN_DELIVERABLES_PATH=/tmp/trigger-dev-deliverables  # Output directory

# AI Provider Configuration (Optional)
CFN_CUSTOM_ROUTING=true                  # Enable custom provider routing
CFN_DEFAULT_PROVIDER=zai                 # Default to Z.ai for cost optimization
ZAI_API_KEY=...                          # Z.ai API key
KIMI_API_KEY=...                         # Kimi API key
OPENROUTER_API_KEY=...                   # OpenRouter API key
```

### Docker Compose Integration

The worker is configured in `docker-compose.yml`:

```yaml
trigger-worker:
  build:
    context: ../..
    dockerfile: docker/trigger-dev/Dockerfile.worker
  image: trigger-dev-worker-cfn:latest
  container_name: trigger-dev-worker
  volumes:
    - /tmp/trigger-dev-deliverables:/tmp/trigger-dev-deliverables
    - ../..:/workspace:rw  # Project root for agent access
    - ../../.env:/workspace/.env:ro  # API keys
    - /var/run/docker.sock:/var/run/docker.sock  # Docker-in-Docker
  networks:
    - trigger-cfn-network
  restart: unless-stopped
```

## Agent Execution

### How Agents are Loaded

1. **Agent Type Selection**: Specified via `AGENT_TYPE` environment variable
2. **Template Location**: `claude-assets/agents/cfn-dev-team/developers/[agent-type].md`
3. **Provider Routing**: Determined by agent template frontmatter or default provider
4. **Execution**: `npx claude-flow-novice agent [agent-type] --task-id [id]`

### Agent Template Structure

Each agent template includes provider parameters:

```markdown
---
name: backend-developer
description: Backend development specialist
tools: [Read, Write, Edit, Bash, Grep]
model: sonnet
type: specialist
---

<!-- PROVIDER_PARAMETERS
provider: zai
model: glm-4.6
-->
```

### Supported Agent Types

Currently available agent templates:
- `backend-developer` - Backend API and service development
- `react-frontend-engineer` - React/TypeScript frontend development
- `devops-engineer` - Infrastructure and deployment automation
- `tester` - Test implementation and validation
- `reviewer` - Code review and quality assessment

**Note:** All agent templates are located in `claude-assets/agents/cfn-dev-team/`.

## AI Provider Routing

### Default Provider (Z.ai)

When `CFN_CUSTOM_ROUTING=true` and no explicit provider is set in agent template:
- **Provider**: Z.ai
- **Model**: glm-4.6
- **Cost**: $0.50/1M tokens (95-98% savings vs Anthropic)

### Explicit Provider Configuration

Agents can specify custom providers in their templates:

```markdown
<!-- PROVIDER_PARAMETERS
provider: kimi
model: moonshot-v1-8k
-->
```

### Available Providers

| Provider | Model | Cost/1M Tokens | Use Case |
|----------|-------|----------------|----------|
| **zai** | glm-4.6 | $0.50 | Cost-optimized (default) |
| **kimi** | moonshot-v1-8k | $2.00 | Mid-range quality |
| **openrouter** | Various | Varies | Access 400+ models |
| **anthropic** | claude-3-5-sonnet | $15.00 | Premium quality |

## Docker-in-Docker Support

### Per-Agent Container Spawning

The worker supports spawning individual containers for each agent execution:

```bash
# Example: Spawn backend-developer agent in isolated container
docker run --rm \
  --name agent-backend-dev-$TASK_ID \
  --network trigger-cfn-network \
  -e AGENT_TYPE="backend-developer" \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  -e CFN_WORKSPACE="/workspace" \
  -v /workspace:/workspace:rw \
  -v /workspace/.env:/workspace/.env:ro \
  trigger-dev-worker-cfn:latest \
  npx claude-flow-novice agent backend-developer --task-id "$TASK_ID"
```

### Volume Mounts Required

```yaml
volumes:
  # Project root (read/write for agent file operations)
  - /path/to/project:/workspace:rw

  # Environment file (read-only for API keys)
  - /path/to/project/.env:/workspace/.env:ro

  # Docker socket (for per-agent spawning)
  - /var/run/docker.sock:/var/run/docker.sock

  # Deliverables output (agent results)
  - /tmp/trigger-dev-deliverables:/tmp/trigger-dev-deliverables
```

## Testing

### Automated Test Suite

Comprehensive test suite located at `tests/trigger-dev/test-worker-image.sh`:

```bash
# Run all tests
./tests/trigger-dev/test-worker-image.sh
```

### Test Coverage

The test suite validates:

1. **Image Build** - Worker image builds successfully with all dependencies
2. **Agent Profile Loading** - backend-developer template loads correctly from mounted volume
3. **Default Provider Routing** - Z.ai glm-4.6 provider defaults when `CFN_CUSTOM_ROUTING=true`
4. **Explicit Provider** - Kimi provider configuration via environment variables
5. **Clean Exit** - Container shuts down gracefully with exit code 0
6. **Error Handling** - Invalid agent type handled without catastrophic failure

### Manual Testing

#### Test 1: Build Image

```bash
# Build worker image (recommended - 96% faster)
./.claude/skills/docker-build/build.sh \
  --dockerfile docker/trigger-dev/Dockerfile.worker \
  --tag trigger-dev-worker-cfn:latest

# Verify image exists
docker images | grep trigger-dev-worker-cfn
```

#### Test 2: Verify Agent Templates Accessible

```bash
# Start container with backend-developer agent type
docker run -d \
  --name test-worker-profile \
  --network trigger-cfn-network \
  -e AGENT_TYPE="backend-developer" \
  -e CFN_WORKSPACE="/workspace" \
  -v $(pwd):/workspace:rw \
  trigger-dev-worker-cfn:latest \
  sh -c "ls -la /workspace/claude-assets/agents/cfn-dev-team/developers/ && sleep 5"

# Check logs for agent template listing
docker logs test-worker-profile

# Verify backend-developer.md is accessible
docker exec test-worker-profile test -f /workspace/claude-assets/agents/cfn-dev-team/developers/backend-developer.md
echo $?  # Should output 0 (success)

# Cleanup
docker rm -f test-worker-profile
```

#### Test 3: Test Provider Routing

```bash
# Test default Z.ai routing
docker run -d \
  --name test-worker-zai \
  --network trigger-cfn-network \
  -e AGENT_TYPE="backend-developer" \
  -e CFN_CUSTOM_ROUTING="true" \
  -e NODE_ENV="development" \
  trigger-dev-worker-cfn:latest \
  sh -c "env | grep -E '(CFN|PROVIDER)' && sleep 5"

# Check environment variables
docker logs test-worker-zai

# Cleanup
docker rm -f test-worker-zai
```

#### Test 4: Test Explicit Provider (Kimi)

```bash
# Test Kimi provider routing
docker run -d \
  --name test-worker-kimi \
  --network trigger-cfn-network \
  -e AGENT_TYPE="backend-developer" \
  -e CFN_CUSTOM_ROUTING="true" \
  -e CFN_DEFAULT_PROVIDER="kimi" \
  -e KIMI_API_KEY="test-key" \
  trigger-dev-worker-cfn:latest \
  sh -c "env | grep -E '(PROVIDER|KIMI)' && sleep 5"

# Verify KIMI_API_KEY is set
docker exec test-worker-kimi sh -c 'test -n "$KIMI_API_KEY"'
echo $?  # Should output 0 (success)

# Cleanup
docker rm -f test-worker-kimi
```

#### Test 5: Test Container Exit

```bash
# Test clean exit
docker run -d \
  --name test-worker-exit \
  --network trigger-cfn-network \
  trigger-dev-worker-cfn:latest \
  sh -c "echo 'Worker started' && sleep 1 && echo 'Worker exiting' && exit 0"

# Wait for exit
sleep 3

# Check exit code
docker inspect --format='{{.State.ExitCode}}' test-worker-exit
# Should output 0

# Cleanup
docker rm -f test-worker-exit
```

#### Test 6: Test Error Handling

```bash
# Test invalid agent type
docker run -d \
  --name test-worker-invalid \
  --network trigger-cfn-network \
  -e AGENT_TYPE="nonexistent-agent" \
  -e CFN_WORKSPACE="/workspace" \
  -v $(pwd):/workspace:rw \
  trigger-dev-worker-cfn:latest \
  sh -c "ls /workspace/claude-assets/agents/cfn-dev-team/developers/nonexistent-agent.md 2>&1; exit 0"

# Check logs for error handling
docker logs test-worker-invalid
# Should show "No such file or directory" or similar

# Cleanup
docker rm -f test-worker-invalid
```

### Expected Test Results

All tests should pass with these outcomes:

| Test | Expected Result |
|------|----------------|
| **Test 1** | Image builds successfully, contains Node.js environment |
| **Test 2** | backend-developer.md accessible, container runs without errors |
| **Test 3** | CFN_CUSTOM_ROUTING=true shown, Z.ai is default provider |
| **Test 4** | KIMI_API_KEY set correctly, Kimi provider configured |
| **Test 5** | Container exits with code 0, logs show clean shutdown |
| **Test 6** | Missing file error reported, container doesn't crash |

### Troubleshooting Tests

#### Image Build Fails

```bash
# Check Docker version
docker --version  # Should be 20.10+ or later

# Verify Docker daemon running
docker ps

# Check disk space
df -h

# Try rebuild without cache
./.claude/skills/docker-build/build.sh --no-cache \
  --dockerfile docker/trigger-dev/Dockerfile.worker \
  --tag trigger-dev-worker-cfn:latest
```

#### Agent Template Not Found

```bash
# Verify agent template exists
ls -la claude-assets/agents/cfn-dev-team/developers/backend-developer.md

# Check volume mount path
docker run --rm -v $(pwd):/workspace:rw alpine ls -la /workspace/claude-assets/agents/

# Verify PWD is project root
echo $PWD  # Should be /path/to/claude-flow-novice
```

#### Provider Routing Issues

```bash
# Check environment variables are passed
docker inspect test-worker-zai | grep -A 20 Env

# Verify CFN_CUSTOM_ROUTING in docker-compose
grep -A 10 "trigger-worker:" docker/trigger-dev/docker-compose.yml | grep CFN_CUSTOM_ROUTING

# Check .env file exists
test -f .env && echo "Found" || echo "Missing"
```

## Production Deployment

### Build for Production

```bash
# Build optimized image
NODE_ENV=production ./.claude/skills/docker-build/build.sh \
  --dockerfile docker/trigger-dev/Dockerfile.worker \
  --tag trigger-dev-worker-cfn:v1.0.0

# Tag for registry
docker tag trigger-dev-worker-cfn:v1.0.0 \
  registry.example.com/trigger-dev-worker-cfn:v1.0.0

# Push to registry
docker push registry.example.com/trigger-dev-worker-cfn:v1.0.0
```

### Security Considerations

1. **API Keys**: Never commit `.env` file to version control
2. **Docker Socket**: Restrict access to `/var/run/docker.sock` in production
3. **Volume Permissions**: Use read-only mounts where possible
4. **Network Isolation**: Use Docker networks for service isolation
5. **Image Scanning**: Scan images for vulnerabilities before deployment

### Monitoring

#### Health Checks

```bash
# Check worker container health
docker ps --filter "name=trigger-worker" --format "table {{.Names}}\t{{.Status}}"

# View worker logs
docker logs trigger-dev-worker --tail=50 --follow

# Check trigger.dev job queue
docker exec trigger-dev-redis redis-cli LLEN "trigger:queue:default"
```

#### Metrics

Monitor these metrics in production:
- Container CPU/memory usage
- Job processing rate (jobs/minute)
- Average job duration
- Error rate (failed jobs / total jobs)
- Agent spawn success rate

## Migration from spawn-workers.js

The worker image replaces the legacy `spawn-workers.js` orchestration:

### Old Pattern (spawn-workers.js)

```javascript
// Legacy: Node.js script spawning agents
const agents = ['backend-dev', 'tester', 'reviewer'];
for (const agent of agents) {
  await spawnAgent(agent, taskId);
}
```

### New Pattern (Trigger.dev Jobs)

```typescript
// Modern: Trigger.dev job orchestration
export const cfnLoopJob = client.defineJob({
  id: "cfn-loop-execution",
  name: "CFN Loop Agent Execution",
  trigger: { event: { name: "cfn.loop.start" } },
  run: async (payload, io, ctx) => {
    // Agent execution handled by worker container
    const result = await io.runTask("execute-agent", async () => {
      // Worker container spawns agent with proper isolation
      return executeAgent(payload.agentType, payload.taskId);
    });
    return result;
  },
});
```

### Migration Benefits

1. **Isolation**: Each agent runs in isolated container
2. **Scalability**: Workers scale independently of webapp
3. **Reliability**: Failed jobs automatically retry
4. **Monitoring**: Trigger.dev dashboard provides visibility
5. **Cost Optimization**: Custom provider routing reduces API costs by 95-98%

## References

- **Trigger.dev Documentation**: https://trigger.dev/docs
- **Docker-in-Docker**: https://hub.docker.com/_/docker
- **CFN Loop Architecture**: `docs/CFN_LOOP_ARCHITECTURE.md`
- **Custom Provider Routing**: `docs/CUSTOM_PROVIDER_ROUTING.md`
- **Agent Templates**: `claude-assets/agents/cfn-dev-team/README.md`

---

**Last Updated**: 2025-11-23
**Version**: 1.0.0
**Maintained By**: Backend Developer Agent (Phase 1.1 Trigger.dev Integration)
