Skip to main content
Clanker provides a unified natural language interface across multiple cloud providers. You can ask questions or generate infrastructure plans for AWS, GCP, Azure, and Cloudflare using the same CLI.

Supported providers

AWS

Agent: internal/aws/
CLI: aws
Services: EC2, Lambda, S3, RDS, ECS, EKS, CloudWatch, etc.

GCP

Agent: internal/gcp/
CLI: gcloud
Services: Compute Engine, Cloud Run, GKE, BigQuery, etc.

Azure

Agent: internal/azure/
CLI: az
Services: App Service, Cosmos DB, AKS, Functions, etc.

Cloudflare

Agent: internal/cloudflare/
CLI: wrangler / API
Services: Workers, KV, D1, R2, WAF, DNS, Zero Trust

How routing works

Clanker automatically detects which provider to use based on your question:
1

Keyword detection

The routing system checks for provider-specific keywords:
  • AWS: ec2, lambda, s3, rds, cloudwatch, dynamodb
  • GCP: gcloud, compute engine, cloud run, bigquery, gke
  • Azure: azure, app service, cosmos db, aks, functions
  • Cloudflare: cloudflare, workers, waf, dns, tunnel
2

LLM classification (if ambiguous)

If multiple providers are detected, an LLM classifies the question.See internal/routing/classifier.go.
3

Agent dispatch

The appropriate agent handles the request:
  • AWS agent: Multi-agent architecture with semantic analysis
  • GCP agent: GCP CLI operations and resource queries
  • Azure agent: Azure CLI operations and resource queries
  • Cloudflare agent: Sub-agents for Workers, WAF, DNS, Zero Trust, Analytics
if !includeAWS && !includeGitHub && !includeTerraform && !includeGCP && !includeAzure && !includeCloudflare {
    routingQuestion := questionForRouting(question)

    // First, do quick keyword check for explicit terms
    svcCtx := routing.InferContext(routingQuestion)
    includeAWS = svcCtx.AWS
    includeGitHub = svcCtx.GitHub

    if debug {
        fmt.Printf("Keyword inference: AWS=%v, GitHub=%v, Terraform=%v, K8s=%v, GCP=%v, Cloudflare=%v\n",
            svcCtx.AWS, svcCtx.GitHub, svcCtx.Terraform, svcCtx.K8s, svcCtx.GCP, svcCtx.Cloudflare)
    }

    // For ambiguous queries (multiple services detected or Cloudflare detected),
    // use LLM to make the final routing decision
    if routing.NeedsLLMClassification(svcCtx) {
        if debug {
            fmt.Println("[routing] Ambiguous query detected, using LLM for classification...")
        }

        llmService, err := routing.ClassifyWithLLM(context.Background(), routingQuestion, debug)
        if err != nil {
            // FALLBACK: LLM classification failed, use keyword-based inference
            if debug {
                fmt.Printf("[routing] LLM classification failed (%v), falling back to keyword inference\n", err)
            }
            // Keep the keyword-inferred values as-is (no changes needed)
        } else {
            // LLM succeeded - override keyword-based inference with LLM decision
            routing.ApplyLLMClassification(&svcCtx, llmService)

            if debug {
                fmt.Printf("LLM override: AWS=%v, K8s=%v, GCP=%v, Azure=%v, Cloudflare=%v\n",
                    svcCtx.AWS, svcCtx.K8s, svcCtx.GCP, svcCtx.Azure, svcCtx.Cloudflare)
            }
        }
    }

    // Handle inferred Terraform context
    if svcCtx.Terraform {
        includeTerraform = true
    }

    if svcCtx.GCP {
        includeGCP = true
    }

    if svcCtx.Azure {
        includeAzure = true
    }

    // Update includeAWS and includeGitHub from service context
    includeAWS = svcCtx.AWS
    includeGitHub = svcCtx.GitHub
    includeAzure = svcCtx.Azure

    // Handle Cloudflare queries by delegating to Cloudflare agent
    if svcCtx.Cloudflare {
        return handleCloudflareQuery(context.Background(), routingQuestion, debug)
    }
}

Provider-specific features

AWS

The AWS agent uses the multi-agent architecture with semantic analysis:
  • Parallel agents: Log, Metrics, Infrastructure, Security, Performance, Cost, etc.
  • Decision trees: Maps user intent to agent strategies
  • Tool calling: LLM can execute AWS CLI operations directly
clanker ask "Why is my Lambda function timing out?"
See AI agents for details.

GCP

The GCP agent queries Google Cloud resources using the gcloud CLI:
clanker ask --gcp "List all Cloud Run services"
Supported operations:
  • List Compute Engine instances
  • Query Cloud Run services
  • Inspect GKE clusters
  • Check BigQuery datasets
  • View Cloud Functions

Azure

The Azure agent queries Azure resources using the az CLI:
clanker ask --azure "Show me all App Services"
Supported operations:
  • List App Services
  • Query Cosmos DB accounts
  • Inspect AKS clusters
  • View Azure Functions
  • Check storage accounts

Cloudflare

The Cloudflare agent routes to specialized sub-agents:
Manages firewall rules, rate limiting, and DDoS protection.
clanker ask --cloudflare "Show all WAF rules"
Keywords: firewall, waf, rate limit, ddos, bot, security level
Manages Workers, KV, D1, R2, Durable Objects, and Pages.
clanker ask --cloudflare "List all Workers"
Keywords: worker, kv, d1, r2, pages, durable object
Queries traffic, bandwidth, and performance metrics.
clanker ask --cloudflare "Show traffic analytics for the last 24 hours"
Keywords: analytics, traffic, bandwidth, requests, visitors, performance metrics
Manages Tunnels, Access apps, and policies.
clanker ask --cloudflare "List all Cloudflare Tunnels"
Keywords: tunnel, access app, access policy, zero trust, cloudflared, warp
Manages DNS records and zones.
clanker ask --cloudflare "Show DNS records for example.com"
Keywords: dns, record, zone, domain
questionLower := strings.ToLower(question)

// Check for WAF/Security queries
isWAF := strings.Contains(questionLower, "firewall") ||
    strings.Contains(questionLower, "waf") ||
    strings.Contains(questionLower, "rate limit") ||
    strings.Contains(questionLower, "security level") ||
    strings.Contains(questionLower, "under attack") ||
    strings.Contains(questionLower, "ddos") ||
    strings.Contains(questionLower, "bot")

if isWAF {
    wafAgent := cfwaf.NewSubAgent(client, debug)
    opts := cfwaf.QueryOptions{}
    response, err := wafAgent.HandleQuery(ctx, question, opts)
    // ...
}

// Check for Workers queries
isWorkers := strings.Contains(questionLower, "worker") ||
    strings.Contains(questionLower, "kv") ||
    strings.Contains(questionLower, "d1") ||
    strings.Contains(questionLower, "r2") ||
    strings.Contains(questionLower, "pages") ||
    strings.Contains(questionLower, "durable object")

if isWorkers {
    workersAgent := cfworkers.NewSubAgent(client, debug)
    opts := cfworkers.QueryOptions{
        AccountID: client.GetAccountID(),
    }
    response, err := workersAgent.HandleQuery(ctx, question, opts)
    // ...
}

Maker mode: Multi-cloud plans

Maker mode supports all four providers for infrastructure automation:

AWS plans

clanker ask --maker "Create an S3 bucket with encryption"
Generates a plan with "provider": "aws" and aws CLI commands.

GCP plans

clanker ask --maker --gcp "Deploy a Cloud Run service"
Generates a plan with "provider": "gcp" and gcloud commands.

Azure plans

clanker ask --maker --azure "Create an App Service"
Generates a plan with "provider": "azure" and az commands.

Cloudflare plans

clanker ask --maker --cloudflare "Deploy a Cloudflare Worker"
Generates a plan with "provider": "cloudflare" and wrangler commands.
makerProvider := "aws"
makerProviderReason := "default"
explicitGCP := cmd.Flags().Changed("gcp") && includeGCP
explicitAWS := cmd.Flags().Changed("aws") && includeAWS
explicitCloudflare := cmd.Flags().Changed("cloudflare") && includeCloudflare
explicitAzure := cmd.Flags().Changed("azure") && includeAzure
explicitCount := 0
if explicitGCP {
    explicitCount++
}
if explicitAWS {
    explicitCount++
}
if explicitCloudflare {
    explicitCount++
}
if explicitAzure {
    explicitCount++
}
if explicitCount > 1 {
    return fmt.Errorf("cannot use multiple provider flags (--aws, --gcp, --azure, --cloudflare) together with --maker")
}
switch {
case explicitCloudflare:
    makerProvider = "cloudflare"
    makerProviderReason = "explicit"
case explicitAzure:
    makerProvider = "azure"
    makerProviderReason = "explicit"
case explicitGCP:
    makerProvider = "gcp"
    makerProviderReason = "explicit"
case explicitAWS:
    makerProvider = "aws"
    makerProviderReason = "explicit"
default:
    svcCtx := routing.InferContext(questionForRouting(question))
    if svcCtx.Cloudflare {
        makerProvider = "cloudflare"
        makerProviderReason = "inferred"
    } else if svcCtx.Azure {
        makerProvider = "azure"
        makerProviderReason = "inferred"
    } else if svcCtx.GCP {
        makerProvider = "gcp"
        makerProviderReason = "inferred"
    }
}

_, _ = fmt.Fprintf(os.Stderr, "[maker] provider=%s (%s)\n", makerProvider, makerProviderReason)

Credential management

Clanker supports multiple credential sources:

AWS

Uses standard AWS profiles from ~/.aws/config:
clanker ask "List EC2 instances" --profile production

GCP

Uses gcloud auth application-default login.

Azure

Uses az login credentials.

Cloudflare

Uses CLOUDFLARE_API_TOKEN or CF_API_TOKEN env var.

Force provider selection

Override automatic routing with explicit flags:
# Force AWS agent
clanker ask "List instances" --aws

# Force GCP agent
clanker ask "List instances" --gcp

# Force Azure agent
clanker ask "List instances" --azure

# Force Cloudflare agent
clanker ask "List zones" --cloudflare

Example workflows

Query across providers

# AWS
clanker ask "Show Lambda functions with high error rates"

# GCP
clanker ask --gcp "List Cloud Run services in us-central1"

# Azure
clanker ask --azure "Show all App Services in East US"

# Cloudflare
clanker ask --cloudflare "Show WAF rules blocking traffic"

Generate multi-cloud plans

# AWS S3 bucket
clanker ask --maker "Create an S3 bucket for logs" > aws-plan.json

# GCP Cloud Storage bucket
clanker ask --maker --gcp "Create a Cloud Storage bucket for logs" > gcp-plan.json

# Azure Storage account
clanker ask --maker --azure "Create a Storage account for logs" > azure-plan.json

# Cloudflare R2 bucket
clanker ask --maker --cloudflare "Create an R2 bucket for logs" > cf-plan.json

Next steps

Natural language

Learn how Clanker interprets your questions

Maker mode

Generate infrastructure plans from natural language

Build docs developers (and LLMs) love