Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 10 additions & 72 deletions server/chat/backend/agent/skills/core/cloud_access.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,10 @@
UNIVERSAL CLOUD ACCESS:
cloud_exec(provider, 'COMMAND') gives you COMPLETE access to cloud platforms:
- GCP: cloud_exec('gcp', 'ANY_GCLOUD_COMMAND') - Full Google Cloud access
- Azure: cloud_exec('azure', 'ANY_AZ_COMMAND') - Full Microsoft Azure access
- AWS: cloud_exec('aws', 'ANY_AWS_COMMAND') - Full Amazon Web Services access
- OVH: cloud_exec('ovh', 'ANY_OVHCLOUD_COMMAND') - Full OVHcloud access
- Scaleway: cloud_exec('scaleway', 'ANY_SCW_COMMAND') - Full Scaleway access
- Authentication and project/subscription setup handled automatically
- NEVER give manual console instructions when a CLI command exists

AZURE RESOURCE GROUP REQUIREMENTS:
When working with Azure, resources MUST be created within a resource group. Before creating any Azure resources:
1. ALWAYS check for existing resource groups first: cloud_exec('azure', 'group list')
2. If suitable resource groups exist, use one of them for your resources
3. If no suitable resource group exists, create a new one: cloud_exec('azure', 'group create --name <name> --location <location>')
4. Then proceed with resource creation, always specifying the resource group
- This applies to ALL Azure resources: VMs, storage accounts, networks, databases, etc.

CAPABILITY DISCOVERY:
When facing ANY cloud management task you're unsure about:

For GCP:
1. EXPLORE the gcloud CLI: cloud_exec('gcp', 'help | grep KEYWORD')
2. Get command help: cloud_exec('gcp', 'CATEGORY --help')
3. Try beta commands: cloud_exec('gcp', 'beta CATEGORY --help')
4. List services: cloud_exec('gcp', 'services list --available')

For Azure:
1. EXPLORE the az CLI: cloud_exec('azure', 'help | grep KEYWORD')
2. Get command help: cloud_exec('azure', 'CATEGORY --help')
3. List services: cloud_exec('azure', 'provider list')
4. Find resources: cloud_exec('azure', 'resource list')

For OVH (CRITICAL - follow this EXACT workflow for instance creation):
1. **Get project ID**: cloud_exec('ovh', 'cloud project list --json')
2. **Get ACTUAL regions** (DO NOT assume - US/EU accounts have different regions!):
cloud_exec('ovh', 'cloud region list --cloud-project <PROJECT_ID> --json')
3. **Get flavors for region**: cloud_exec('ovh', 'cloud reference list-flavors --cloud-project <PROJECT_ID> --region <REGION> --json')
4. **Get images**: cloud_exec('ovh', 'cloud reference list-images --cloud-project <PROJECT_ID> --region <REGION> --json')
5. **Create instance WITH inline SSH key** (REQUIRED - use this exact syntax):
cloud_exec('ovh', 'cloud instance create <REGION> --name <NAME> --boot-from.image <IMAGE_ID> --flavor <FLAVOR_ID> --network.public --ssh-key.create.name <KEY_NAME> --ssh-key.create.public-key "<PUBLIC_KEY>" --cloud-project <PROJECT_ID> --wait --json')
KEY RULES: --cloud-project (NOT --project-id), region is POSITIONAL, --network.public (NEVER --network <ID>)

For Scaleway:
1. **ALWAYS use cloud_exec('scaleway', ...)** - NOT terminal_exec! (credentials are auto-configured)
2. List instances: cloud_exec('scaleway', 'instance server list')
3. Get help: cloud_exec('scaleway', 'instance server create --help')
4. Create instance: cloud_exec('scaleway', 'instance server create type=DEV1-S image=ubuntu_jammy name=my-vm')
5. Scaleway uses key=value syntax, NOT --key value

All CLIs can do EVERYTHING - quotas, billing, IAM, networking, storage, compute, etc.
Your job is to DISCOVER and USE the right commands, not give manual instructions.

The system uses service account/service principal authentication automatically - no manual auth needed.

IMPORTANT VM CREATION RULES:
- Azure VMs: The system automatically generates strong admin passwords using Terraform's random_password resource. You do NOT need to ask users for passwords or SSH keys.
- When deploying Azure VMs, proceed directly with deployment - authentication is handled automatically.

IMPORTANT: When writing custom Terraform code:
- DO NOT just add comments saying to adjust regions
- ACTUALLY USE the correct zone in your code
- The zone in your terraform MUST match the user's geographic requirements

REGION MAPPING (use when user specifies a geography):
- Canada: GCP northamerica-northeast1-a / northamerica-northeast2-a, AWS ca-central-1, Azure canadacentral
- Belgium/EU: GCP europe-west1-a, AWS eu-west-1, Azure westeurope
- London/UK: GCP europe-west2-a, AWS eu-west-2, Azure uksouth
- Singapore/SEA: GCP asia-southeast1-a, AWS ap-southeast-1, Azure southeastasia
- Tokyo/Japan: GCP asia-northeast1-a, AWS ap-northeast-1, Azure japaneast
- US (default): GCP us-central1-b, AWS us-east-1, Azure eastus
- If user says 'NOT US', prefer Canada (northamerica-northeast1-a / ca-central-1)
CLOUD ACCESS:
cloud_exec(provider, 'COMMAND') gives you full access to cloud platforms:
- GCP: cloud_exec('gcp', 'gcloud/gsutil/bq/kubectl COMMAND')
- AWS: cloud_exec('aws', 'aws/kubectl/eksctl COMMAND')
- Azure: cloud_exec('azure', 'az/kubectl COMMAND')
- OVH: cloud_exec('ovh', 'ovhcloud COMMAND')
- Scaleway: cloud_exec('scaleway', 'scw COMMAND')

Authentication is automatic — never ask users for credentials or give manual console instructions.
If a cloud command fails or returns unexpected results, call load_skill with the provider name (e.g., load_skill('aws')) to get the full CLI reference before retrying.
1 change: 1 addition & 0 deletions server/chat/backend/agent/skills/core/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ERROR HANDLING & PERSISTENCE - CRITICAL:
- ALWAYS explain what went wrong and suggest next steps or try alternative approaches
- If you cannot resolve an error, clearly explain the issue to the user rather than ending without explanation
- PROACTIVE ERROR RESOLUTION: If a diagnostic command fails, try alternative commands or data sources autonomously. However, if access is denied or authentication fails, report the issue and pivot to other available data sources rather than attempting to bypass the access control.
- CLOUD COMMAND FAILURES: If a cloud_exec command fails (wrong syntax, unknown flag, unexpected error), call load_skill with the provider name BEFORE retrying. The skill contains the correct CLI reference. Example: load_skill('aws'), load_skill('gcp'), load_skill('ovh').
- For unfamiliar errors or recent changes, use web_search to find current solutions: web_search('error message troubleshooting', 'provider', 3)
- Check for breaking changes or deprecations: web_search('service deprecation breaking changes', 'provider', 2, True)
- For application errors: If GitHub is connected, review application code, configuration files, and recent commits using GitHub MCP tools
Expand Down
223 changes: 223 additions & 0 deletions server/chat/backend/agent/skills/integrations/aws/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
name: aws
id: aws
description: "AWS integration — EC2, EKS, RDS, S3, Lambda, CloudWatch, IAM, VPC, ELB via CLI"
category: cloud_provider
connection_check:
method: provider_in_preference
tools:
- cloud_exec
index: "AWS — EC2, EKS, RDS, S3, Lambda, CloudWatch, IAM, VPC"
rca_priority: 10
allowed-tools: cloud_exec
metadata:
author: aurora
version: "2.0"
---

# AWS Integration

## Overview
Full Amazon Web Services access via `cloud_exec('aws', 'COMMAND')`.
Available CLIs: `aws`, `kubectl`, `eksctl`, `helm`.
Authentication is automatic — never ask users for credentials.

## Multi-Account Support (CRITICAL)
- First `cloud_exec('aws', ...)` call (without `account_id`) fans out to ALL connected accounts and returns `results_by_account`.
- Inspect results to identify which account(s) are relevant.
- ALL subsequent calls MUST include `account_id='<ACCOUNT_ID>'`.
- NEVER keep querying all accounts after you've identified the right one.

```python
# Step 1: fan-out discovery
cloud_exec('aws', 'ec2 describe-instances --query "Reservations[].Instances[].{ID:InstanceId,State:State.Name}" --output json')
# Step 2: target specific account
cloud_exec('aws', 'ec2 describe-instances --instance-ids i-abc123', account_id='123456789012')
```

## CLI Reference

### Identity & Discovery
```python
cloud_exec('aws', 'sts get-caller-identity', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-regions --output table', account_id='<ACCT>')
cloud_exec('aws', 'organizations describe-account --account-id <ACCT>', account_id='<ACCT>')
```

### EC2 (Compute)
```python
cloud_exec('aws', 'ec2 describe-instances --query "Reservations[].Instances[].{ID:InstanceId,Type:InstanceType,State:State.Name,Name:Tags[?Key==`Name`].Value|[0],AZ:Placement.AvailabilityZone}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-instances --instance-ids <ID> --output json', account_id='<ACCT>')
cloud_exec('aws', 'ec2 start-instances --instance-ids <ID>', account_id='<ACCT>')
cloud_exec('aws', 'ec2 stop-instances --instance-ids <ID>', account_id='<ACCT>')
cloud_exec('aws', 'ec2 terminate-instances --instance-ids <ID>', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-instance-status --instance-ids <ID>', account_id='<ACCT>')
# Filter by tag:
cloud_exec('aws', 'ec2 describe-instances --filters "Name=tag:Environment,Values=production" --output table', account_id='<ACCT>')
# Filter by state:
cloud_exec('aws', 'ec2 describe-instances --filters "Name=instance-state-name,Values=running" --output table', account_id='<ACCT>')
```

### EKS (Kubernetes)
```python
cloud_exec('aws', 'eks list-clusters', account_id='<ACCT>')
cloud_exec('aws', 'eks describe-cluster --name <CLUSTER>', account_id='<ACCT>')
# MANDATORY before any kubectl: get kubeconfig
cloud_exec('aws', 'eks update-kubeconfig --name <CLUSTER> --region <REGION>', account_id='<ACCT>')
# Then kubectl works:
cloud_exec('aws', 'kubectl get pods -n <NS> -o wide', account_id='<ACCT>')
cloud_exec('aws', 'kubectl describe pod <POD> -n <NS>', account_id='<ACCT>')
cloud_exec('aws', 'kubectl logs <POD> -n <NS> --since=1h --tail=200', account_id='<ACCT>')
cloud_exec('aws', 'kubectl get events -n <NS> --sort-by=.lastTimestamp', account_id='<ACCT>')
cloud_exec('aws', 'kubectl top pods -n <NS>', account_id='<ACCT>')
cloud_exec('aws', 'kubectl get hpa -n <NS>', account_id='<ACCT>')
cloud_exec('aws', 'kubectl rollout history deployment/<DEPLOY> -n <NS>', account_id='<ACCT>')
# Node pool info:
cloud_exec('aws', 'eks list-nodegroups --cluster-name <CLUSTER>', account_id='<ACCT>')
cloud_exec('aws', 'eks describe-nodegroup --cluster-name <CLUSTER> --nodegroup-name <NG>', account_id='<ACCT>')
# Enable control plane logging:
cloud_exec('aws', 'eks update-cluster-config --name <CLUSTER> --logging \'{"clusterLogging": [{"types": ["api", "audit", "scheduler"], "enabled": true}]}\'', account_id='<ACCT>')
```

### S3 (Storage)
```python
cloud_exec('aws', 's3 ls', account_id='<ACCT>')
cloud_exec('aws', 's3 ls s3://<BUCKET>/ --recursive --summarize', account_id='<ACCT>')
cloud_exec('aws', 's3 cp <LOCAL> s3://<BUCKET>/<KEY>', account_id='<ACCT>')
cloud_exec('aws', 's3 rm s3://<BUCKET>/<KEY>', account_id='<ACCT>')
cloud_exec('aws', 's3api get-bucket-policy --bucket <BUCKET>', account_id='<ACCT>')
cloud_exec('aws', 's3api get-bucket-versioning --bucket <BUCKET>', account_id='<ACCT>')
```

### RDS (Databases)
```python
cloud_exec('aws', 'rds describe-db-instances --query "DBInstances[].{ID:DBInstanceIdentifier,Engine:Engine,Version:EngineVersion,Status:DBInstanceStatus,Class:DBInstanceClass,Storage:AllocatedStorage}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'rds describe-db-instances --db-instance-identifier <ID>', account_id='<ACCT>')
cloud_exec('aws', 'rds describe-db-clusters --output table', account_id='<ACCT>')
cloud_exec('aws', 'rds describe-events --source-identifier <ID> --source-type db-instance --duration 1440', account_id='<ACCT>')
# Performance Insights:
cloud_exec('aws', 'pi get-resource-metrics --service-type RDS --identifier db-<RESOURCE_ID> --metric-queries "[{\"Metric\":\"db.load.avg\"}]" --start-time <ISO> --end-time <ISO> --period-in-seconds 300', account_id='<ACCT>')
```

### Lambda (Serverless)
```python
cloud_exec('aws', 'lambda list-functions --query "Functions[].{Name:FunctionName,Runtime:Runtime,Memory:MemorySize,Timeout:Timeout}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'lambda get-function --function-name <NAME>', account_id='<ACCT>')
cloud_exec('aws', 'lambda invoke --function-name <NAME> --payload \'{"key":"value"}\' /dev/stdout', account_id='<ACCT>')
cloud_exec('aws', 'lambda get-function-configuration --function-name <NAME>', account_id='<ACCT>')
cloud_exec('aws', 'lambda list-event-source-mappings --function-name <NAME>', account_id='<ACCT>')
```

### CloudWatch Logs
```python
# List log groups:
cloud_exec('aws', 'logs describe-log-groups --query "logGroups[].{Name:logGroupName,Stored:storedBytes}" --output table', account_id='<ACCT>')
# Filter log events (simple):
cloud_exec('aws', 'logs filter-log-events --log-group-name <GROUP> --start-time <EPOCH_MS> --filter-pattern "ERROR" --limit 50', account_id='<ACCT>')
# Tail recent logs:
cloud_exec('aws', 'logs tail <GROUP> --since 1h --format short', account_id='<ACCT>')
```

### CloudWatch Logs Insights (PREFERRED for complex queries)
Use `start-query` + `get-query-results` for powerful log analysis:
```python
# Start an Insights query (returns queryId):
cloud_exec('aws', 'logs start-query --log-group-name <GROUP> --start-time <EPOCH_SEC> --end-time <EPOCH_SEC> --query-string "fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 50"', account_id='<ACCT>')
# Then fetch results (may need to wait a few seconds):
cloud_exec('aws', 'logs get-query-results --query-id <QUERY_ID>', account_id='<ACCT>')
```
Common Insights query patterns:
- Error frequency: `stats count(*) by bin(5m) | filter @message like /ERROR/`
- Top error messages: `filter @message like /ERROR/ | stats count(*) as cnt by @message | sort cnt desc | limit 20`
- Latency percentiles: `filter @type = "REPORT" | stats avg(@duration), pct(@duration, 95), max(@duration) by bin(5m)`
- Lambda cold starts: `filter @type = "REPORT" | filter @initDuration > 0 | stats count(*) as coldStarts by bin(10m)`

### CloudWatch Metrics & Alarms
```python
cloud_exec('aws', 'cloudwatch describe-alarms --state-value ALARM --output table', account_id='<ACCT>')
cloud_exec('aws', 'cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=<ID> --start-time <ISO> --end-time <ISO> --period 300 --statistics Average Maximum', account_id='<ACCT>')
cloud_exec('aws', 'cloudwatch list-metrics --namespace AWS/RDS --metric-name FreeableMemory', account_id='<ACCT>')
# Common namespaces: AWS/EC2, AWS/RDS, AWS/ELB, AWS/Lambda, AWS/EKS, AWS/S3, AWS/SQS, AWS/SNS
```

### IAM
```python
cloud_exec('aws', 'iam list-roles --query "Roles[].{Name:RoleName,Arn:Arn}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'iam get-role --role-name <ROLE>', account_id='<ACCT>')
cloud_exec('aws', 'iam list-attached-role-policies --role-name <ROLE>', account_id='<ACCT>')
cloud_exec('aws', 'iam get-policy --policy-arn <ARN>', account_id='<ACCT>')
cloud_exec('aws', 'iam simulate-principal-policy --policy-source-arn <ROLE_ARN> --action-names s3:GetObject --resource-arns "arn:aws:s3:::bucket/*"', account_id='<ACCT>')
```

### Networking (VPC)
```python
cloud_exec('aws', 'ec2 describe-vpcs --query "Vpcs[].{ID:VpcId,CIDR:CidrBlock,Name:Tags[?Key==`Name`].Value|[0]}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-subnets --filters "Name=vpc-id,Values=<VPC>" --query "Subnets[].{ID:SubnetId,AZ:AvailabilityZone,CIDR:CidrBlock}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-security-groups --group-ids <SG> --output json', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-route-tables --filters "Name=vpc-id,Values=<VPC>"', account_id='<ACCT>')
cloud_exec('aws', 'ec2 describe-nat-gateways --filter "Name=vpc-id,Values=<VPC>"', account_id='<ACCT>')
```

### Load Balancers
```python
cloud_exec('aws', 'elbv2 describe-load-balancers --query "LoadBalancers[].{Name:LoadBalancerName,DNS:DNSName,State:State.Code,Type:Type}" --output table', account_id='<ACCT>')
cloud_exec('aws', 'elbv2 describe-target-groups --load-balancer-arn <ARN>', account_id='<ACCT>')
cloud_exec('aws', 'elbv2 describe-target-health --target-group-arn <TG_ARN>', account_id='<ACCT>')
cloud_exec('aws', 'elbv2 describe-listeners --load-balancer-arn <ARN>', account_id='<ACCT>')
```

### Other Services
```python
# SQS:
cloud_exec('aws', 'sqs list-queues', account_id='<ACCT>')
cloud_exec('aws', 'sqs get-queue-attributes --queue-url <URL> --attribute-names All', account_id='<ACCT>')
# SNS:
cloud_exec('aws', 'sns list-topics', account_id='<ACCT>')
# Route 53:
cloud_exec('aws', 'route53 list-hosted-zones', account_id='<ACCT>')
cloud_exec('aws', 'route53 list-resource-record-sets --hosted-zone-id <ZONE>', account_id='<ACCT>')
# CloudFormation:
cloud_exec('aws', 'cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE', account_id='<ACCT>')
cloud_exec('aws', 'cloudformation describe-stack-events --stack-name <STACK> --max-items 20', account_id='<ACCT>')
# ECR:
cloud_exec('aws', 'ecr describe-repositories', account_id='<ACCT>')
cloud_exec('aws', 'ecr describe-images --repository-name <REPO> --query "imageDetails[].{Tags:imageTags,Pushed:imagePushedAt,Size:imageSizeInBytes}" --output table', account_id='<ACCT>')
# ECS:
cloud_exec('aws', 'ecs list-clusters', account_id='<ACCT>')
cloud_exec('aws', 'ecs describe-services --cluster <CLUSTER> --services <SVC>', account_id='<ACCT>')
cloud_exec('aws', 'ecs list-tasks --cluster <CLUSTER> --service-name <SVC>', account_id='<ACCT>')
```

## RCA / Investigation Workflow

When investigating an AWS incident:

1. **Identify the account**: First fan-out call to find which account has the affected resources
2. **Get cluster credentials** (if EKS): `eks update-kubeconfig --name <CLUSTER> --region <REGION>`
3. **Check resource state**: `ec2 describe-instances`, `eks describe-cluster`, `rds describe-db-instances`
4. **Check pods/containers** (if K8s): `kubectl get pods -o wide`, `kubectl describe pod`, `kubectl logs`
5. **Check events**: `kubectl get events --sort-by=.lastTimestamp`, `rds describe-events`
6. **Check logs**: CloudWatch `filter-log-events` or Insights `start-query` for patterns
7. **Check metrics**: `cloudwatch get-metric-statistics` for CPU, memory, disk, network
8. **Check alarms**: `cloudwatch describe-alarms --state-value ALARM`
9. **Check recent deployments**: `kubectl rollout history`, `cloudformation describe-stack-events`
10. **Check networking**: Security groups, NACLs, route tables, target health
11. **Compare healthy vs unhealthy**: `kubectl top pods`, instance metrics side-by-side

## Error Recovery

1. **Permission denied** → Check IAM: `iam get-role`, `iam list-attached-role-policies`, `iam simulate-principal-policy`
2. **Resource not found** → Verify region: `ec2 describe-regions`, check account_id
3. **CLI syntax** → `cloud_exec('aws', '<SERVICE> help')` for subcommand reference

### Context7 lookup on failure
For CLI errors:
`mcp_context7_get_library_docs(context7CompatibleLibraryID='/websites/aws_amazon_cli', topic='eks update-kubeconfig')`

## Region Mapping
- US (default): us-east-1
- Canada: ca-central-1
- EU/Belgium: eu-west-1
- UK/London: eu-west-2
- Singapore/SEA: ap-southeast-1
- Tokyo/Japan: ap-northeast-1
Loading
Loading