Skip to main content
Clanker uses a multi-stage natural language processing pipeline to interpret your questions and route them to the appropriate cloud provider agents.

Query routing

When you run clanker ask, your question goes through a routing system that determines which agent(s) should handle it:
1

Extract question

If the prompt contains chat history, extract the last user turn:
cmd/ask.go:1274-1318
func questionForRouting(question string) string {
    trimmed := strings.TrimSpace(question)
    if trimmed == "" {
        return trimmed
    }

    // If the prompt contains a chat transcript (as emitted by clanker-cloud),
    // route based on the last explicit user turn.
    start := strings.LastIndex(trimmed, "\nYou\n")
    startLen := len("\nYou\n")
    if start == -1 && strings.HasPrefix(trimmed, "You\n") {
        start = 0
        startLen = len("You\n")
    }

    if start != -1 {
        candidate := trimmed[start+startLen:]
        // End at next assistant turn marker if present.
        if end := strings.Index(candidate, "\n\nClanker\n"); end != -1 {
            candidate = candidate[:end]
        } else if end := strings.Index(candidate, "\nClanker\n"); end != -1 {
            candidate = candidate[:end]
        }
        candidate = strings.TrimSpace(candidate)
        if candidate != "" {
            return candidate
        }
    }

    return trimmed
}
2

Keyword inference

Check for explicit provider/service keywords:
  • AWS: ec2, lambda, s3, rds, cloudwatch, ecs, eks
  • GCP: gcloud, compute engine, cloud run, bigquery
  • Azure: azure, app service, cosmos db
  • Cloudflare: cloudflare, workers, waf, dns
  • Kubernetes: kubectl, pod, deployment, namespace
  • Terraform: terraform, tfstate, workspace
3

LLM classification (if ambiguous)

If multiple services are detected or Cloudflare is mentioned, use an LLM to make the final routing decision.See internal/routing/classifier.go for the classification prompt.
4

Agent dispatch

Route to the appropriate agent:
  • AWS agent (internal/aws/)
  • GCP agent (internal/gcp/)
  • Azure agent (internal/azure/)
  • Cloudflare agent (internal/cloudflare/)
  • K8s agent (internal/k8s/)
  • IAM agent (internal/iam/)

Semantic intent analysis

For AWS queries, Clanker performs semantic analysis to understand what you’re trying to do without calling external APIs.

Intent classification

The semantic analyzer scores your query against these intent types:
IntentExample keywordsUse case
troubleshooterror, fail, broken, issue, problemDebug failing services
monitorstatus, health, running, uptimeCheck service health
analyzeperformance, slow, bottleneck, optimizePerformance investigation
deploydeploy, launch, create, provisionInfrastructure changes
securityaccess, permission, vulnerability, exposedSecurity audits
costcost, billing, spend, expensiveCost optimization
intentScores := make(map[string]float64)
for intentType, signals := range sa.IntentSignals {
    score := 0.0
    for _, word := range words {
        if weight, exists := signals[word]; exists {
            score += weight
        }
    }
    intentScores[intentType] = score
}

// Select highest-scoring intent
maxScore := 0.0
for intentType, score := range intentScores {
    if score > maxScore {
        maxScore = score
        intent.Primary = intentType
    }
}

Urgency detection

Keywords are weighted to determine urgency:
UrgencyScore thresholdKeywords
Critical≥ 1.0down, outage, emergency, critical
High0.7 - 0.99error, fail, broken, urgent
Medium0.3 - 0.69slow, issue, problem, warning
Low< 0.3(default)
urgencyScore := 0.0
for _, word := range words {
    if weight, exists := sa.UrgencyKeywords[word]; exists {
        urgencyScore += weight
    }
}
switch {
case urgencyScore >= 1.0:
    intent.Urgency = "critical"
case urgencyScore >= 0.7:
    intent.Urgency = "high"
case urgencyScore >= 0.3:
    intent.Urgency = "medium"
default:
    intent.Urgency = "low"
}

Timeframe inference

Certain keywords map to investigation timeframes:
  • now / currentrecent (last 1 hour)
  • todaytoday (last 24 hours)
  • yesterdayyesterday
  • weekweek (last 7 days)
  • monthmonth (last 30 days)

Service identification

The analyzer maintains a mapping of keywords to AWS services:
for service, keywords := range sa.ServiceMapping {
    for _, keyword := range keywords {
        if strings.Contains(queryLower, keyword) {
            intent.TargetServices = append(intent.TargetServices, service)
            break
        }
    }
}
Example service mappings:
  • lambda, functionlambda
  • ec2, instance, serverec2
  • s3, buckets3
  • rds, database, postgres, mysqlrds
  • cloudwatch, logs, metricscloudwatch

Query examples

Here’s how different questions are interpreted:
Question: “Why is my Lambda function timing out?”
{
  "primary": "troubleshoot",
  "confidence": 0.82,
  "target_services": ["lambda", "cloudwatch"],
  "urgency": "high",
  "time_frame": "recent",
  "data_types": ["logs", "metrics", "status"]
}
Agents spawned: Log agent, Metrics agent, Infrastructure agent

Provider-specific routing

Cloudflare queries

Cloudflare questions are routed to specialized sub-agents:
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)
    // ...
}

// 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)
    // ...
}
Sub-agents:
  • WAF agent (internal/cloudflare/waf/): Firewall rules, rate limiting, DDoS protection
  • Workers agent (internal/cloudflare/workers/): Workers, KV, D1, R2, Durable Objects
  • Analytics agent (internal/cloudflare/analytics/): Traffic, bandwidth, performance metrics
  • Zero Trust agent (internal/cloudflare/zerotrust/): Tunnels, Access apps, policies
  • DNS agent (internal/cloudflare/dns/): DNS records, zones

Kubernetes queries

K8s questions are detected by keywords like kubectl, pod, deployment, namespace:
clanker ask "Show me all pods in the default namespace"
The K8s agent (internal/k8s/) handles cluster inspection, resource queries, and health checks.

IAM queries

IAM/security questions are routed to the IAM agent:
clanker ask "What permissions does this role have?" --iam --role-arn arn:aws:iam::123456789012:role/MyRole
The IAM agent (internal/iam/) performs security analysis on roles, policies, and permissions.

Testing routing decisions

Use --route-only to see how your question would be routed without executing:
clanker ask "Deploy a worker to Cloudflare" --route-only
Output:
{
  "agent": "cloudflare",
  "reason": "LLM classification: keyword 'cloudflare' detected"
}
Override routing: Use explicit flags to force a specific provider:
  • --aws: Force AWS agent
  • --gcp: Force GCP agent
  • --azure: Force Azure agent
  • --cloudflare: Force Cloudflare agent
  • --iam: Force IAM agent

Next steps

AI agents

Learn about the multi-agent architecture

Maker mode

Generate infrastructure plans from natural language

Build docs developers (and LLMs) love