Skip to main content
chainforge ships a production-ready HTTP server binary and a one-line embedding API for library users. This guide covers both.

Embedding the server (library usage)

The fastest way to serve an agent over HTTP is chainforge.Serve:
agent, _ := chainforge.NewAgent(
    chainforge.WithAnthropic(os.Getenv("ANTHROPIC_API_KEY"), "claude-sonnet-4-6"),
    chainforge.WithLogging(slog.Default()),
)
log.Fatal(chainforge.Serve(":8080", agent))
Serve blocks until SIGINT or SIGTERM, then performs a 30-second graceful shutdown and calls agent.Close(). No other setup required.

Custom lifecycle

For applications that manage their own signal handling, use ServeContext:
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()

if err := chainforge.ServeContext(ctx, ":8080", agent); err != nil {
    log.Fatal(err)
}

Endpoints exposed by Serve / ServeContext

MethodPathDescription
POST/v1/chatSynchronous chat
POST/v1/chat/streamStreaming chat via SSE
GET/healthzLiveness probe
For /readyz, /v1/info, custom CORS origins, or TLS — use pkg/server directly.

HTTP API

MethodPathDescription
POST/v1/chatSynchronous chat — waits for full response
POST/v1/chat/streamStreaming chat via SSE
GET/healthzLiveness probe
GET/readyzReadiness probe
GET/v1/infoProvider/model metadata

Request format

{ "session_id": "user-123", "message": "Hello!" }

Synchronous response

{
  "message": { "role": "assistant", "content": "Hello! How can I help?" },
  "usage": { "input_tokens": 12, "output_tokens": 9 }
}

Streaming (SSE)

event: text
data: {"delta":"Hello"}

event: text
data: {"delta":"! How can I help?"}

event: done
data: {"stop_reason":"end_turn"}

Configuration

Configuration is loaded from a YAML file with environment variable overrides. API keys are env-only — they cannot appear in YAML files.
# config.example.yaml
host: "0.0.0.0"
port: 8080
provider:
  name: "anthropic"    # "anthropic" | "openai" | "ollama" | "gemini"
model: "claude-sonnet-4-6"
log_level: "info"
log_format: "json"
otel_enabled: false
otel_endpoint: "localhost:4317"
# API keys via environment only
ANTHROPIC_API_KEY=sk-ant-... chainforge-server --config config.yaml
GEMINI_API_KEY=...          chainforge-server --config config.yaml

Docker

# Build
docker build -t chainforge:latest -f deploy/Dockerfile .

# Run
docker run --rm \
  -p 8080:8080 \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  -v $(pwd)/config.example.yaml:/config.yaml:ro \
  chainforge:latest --config /config.yaml
The image uses distroless/static-debian12:nonroot — no shell, uid 65532.

docker-compose

Starts chainforge + Qdrant + OpenTelemetry Collector + Jaeger:
cd deploy/
ANTHROPIC_API_KEY=sk-ant-... docker-compose up -d

# View traces
open http://localhost:16686   # Jaeger UI

Kubernetes

# Apply all manifests
kubectl apply -f deploy/k8s/namespace.yaml
kubectl apply -f deploy/k8s/configmap.yaml

# Inject secrets (never commit real values)
kubectl create secret generic chainforge-secrets \
  --namespace=chainforge \
  --from-literal=ANTHROPIC_API_KEY=sk-ant-... \
  --from-literal=OPENAI_API_KEY=

kubectl apply -f deploy/k8s/deployment.yaml
kubectl apply -f deploy/k8s/service.yaml
kubectl apply -f deploy/k8s/hpa.yaml

# Verify
kubectl rollout status deployment/chainforge -n chainforge
kubectl get pods -n chainforge

Security posture

The Deployment enforces:
  • runAsNonRoot: true — container cannot run as root
  • readOnlyRootFilesystem: true — no writes to container filesystem
  • allowPrivilegeEscalation: false
  • capabilities.drop: ["ALL"]

HPA

The default HPA scales between 2 and 10 replicas at 50% CPU:
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 50

Helm

helm lint deploy/helm/

# Dry run
helm template chainforge deploy/helm/ | kubectl apply --dry-run=client -f -

# Install
helm install chainforge deploy/helm/ \
  --namespace chainforge --create-namespace \
  --set secrets.anthropicApiKey=sk-ant-...

# Upgrade
helm upgrade chainforge deploy/helm/ \
  --set image.tag=0.4.0

# Uninstall (secrets are kept by helm.sh/resource-policy: keep)
helm uninstall chainforge -n chainforge

Key values

ValueDefaultDescription
config.provider.nameanthropicProvider name
config.modelclaude-sonnet-4-6Model identifier
config.otelEnabledfalseEnable OTel tracing
hpa.enabledtrueEnable horizontal pod autoscaler
secrets.anthropicApiKey""Set at install time, never in values.yaml
ingress.enabledfalseEnable ingress