Opensource Infra AI Agent
An opensource Multi-Agent system that works like your Cloud DevOps team. Give commands, audit costs and analyze your AWS Infrastructure in plain english.
OpenKite collapses your entire DevOps console into a single chat prompt. Instead of jumping between the AWS console, Cost Explorer dashboards, CloudWatch tabs, Trusted Advisor, custom Bash scripts, and a folder of Terraform one-offs — you just ask.
It does the work a DevOps engineer would do, on demand:
- Inventory & visibility — list, filter, and inspect EC2, RDS, Lambda, S3, NAT, security groups across regions without touching the console.
- Cost optimization — audit idle compute, orphan EBS, dead Lambdas, lifecycle-less buckets, idle NAT gateways and underused reservations — the same hunt a FinOps engineer runs every quarter.
- Security & compliance checks — flag wide-open security groups and public S3 buckets in seconds, no Trusted Advisor subscription needed.
- Performance triage — pull CloudWatch metrics for any resource (
is i-… idle?,RDS CPU last 14 days?) without writing a single boto3 call. - Safe remediation — stop instances, delete orphan volumes, attach S3 lifecycle rules, retire dead Lambdas — every write action pauses for human approval before it runs.
- Conversational follow-ups — "now delete the smallest one" — threads remember context across turns, just like a teammate would.
One agent. ~30 typed tools. Plain English in, real AWS actions out — with humans in the loop where it matters.
git clone https://github.com/darshil3011/openkite.git
cd openkite
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"OpenKite needs AWS credentials for the tools and one LLM provider key for the agent. Anthropic is the default — pick anything else from Choose your LLM provider below.
# AWS (read-only IAM user is recommended for safety)
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=us-east-1
# Default LLM: Anthropic Claude (https://console.anthropic.com/)
export ANTHROPIC_API_KEY=sk-ant-...Append these to ~/.bashrc (or ~/.zshrc) and source it to make them persistent. Boto3 and the LangChain provider pick up env vars automatically.
If you already use AWS profiles, set AWS_PROFILE=my-readonly-profile instead of the two key/secret vars.
openkite ask "list my running EC2 instances"
openkite ask "is i-03e3c90cd9ea52c82 idle?"
openkite ask "audit my AWS for cost waste"
openkite ask "show me public S3 buckets"
openkite ask "delete volume vol-0abc" # pauses to confirmBrowse the toolbox:
openkite tools$ openkite ask "is i-03e3c90cd9ea52c82 idle?"
→ get_ec2_metric(instance_id='i-03e3c90cd9ea52c82', days=14)
{"average": 0.3, "metric": "CPUUtilization"}
Yes — the instance averaged 0.3% CPU over 14 days. It is idle.
$ openkite ask "audit cost waste in us-east-1"
→ find_idle_ec2(region='us-east-1')
→ find_orphan_ebs(region='us-east-1')
→ find_dead_lambda(region='us-east-1')
→ find_buckets_without_lifecycle(region='us-east-1')
→ find_idle_nat_gateways(region='us-east-1')
Found 11 candidates totalling ~$143/mo:
- 4 idle EC2 instances (proxy, wc-admin-test, wc-admin-prod, ...)
- 1 idle RDS (wc-admin-prod)
- 6 unmanaged S3 buckets
$ openkite ask "delete vol-0abc1234"
→ delete_volume(volume_id='vol-0abc1234')
[confirm] Delete EBS volume vol-0abc1234 in us-east-1? (yes/no): yes
{"volume_id": "vol-0abc1234", "status": "deleted"}
Done — the volume has been deleted.
openkite ask "list orphan EBS volumes" --thread my-cleanup
openkite ask "delete the smallest one" --thread my-cleanup # remembers the list29 typed tools across five service families:
| Category | Tools |
|---|---|
| EC2 | list_ec2_instances, get_ec2_metric, find_idle_ec2, stop_ec2 |
| EBS | list_ebs_volumes, find_orphan_ebs, delete_volume |
| NAT / VPC / SG | list_nat_gateways, get_nat_traffic, find_idle_nat_gateways, delete_nat_gateway, list_security_groups, audit_open_security_groups |
| RDS | list_rds_instances, get_rds_metric, find_idle_rds, stop_rds |
| Lambda | list_lambda_functions, get_lambda_invocation_count, find_dead_lambda, delete_lambda |
| S3 | list_s3_buckets, get_s3_lifecycle, get_s3_public_access, find_buckets_without_lifecycle, audit_public_buckets, put_s3_lifecycle |
| Cost | get_cost_breakdown, get_ri_coverage |
Three layers per service:
- Read primitives (
list_*,get_*) — small, fast, parameterised. - Composite analyzers (
find_*,audit_*) — wrap several primitives to answer "is X bad?". - Write actions (
stop_*,delete_*,put_*) — pause for confirmation viainterrupt()before mutating anything.
Run openkite tools to see live arg signatures.
OpenKite is provider-agnostic. Anthropic is the default; switch to any other provider with two env vars (OPENKITE_PROVIDER + OPENKITE_MODEL) plus that provider's API key. No CLI flags, no code changes.
Run openkite providers to see the live list with default models and install hints.
| Provider | Install | API key env var | Example model |
|---|---|---|---|
| Anthropic (default) | bundled | ANTHROPIC_API_KEY |
claude-haiku-4-5-20251001 |
| OpenAI | pip install 'cloudops-openkite[openai]' |
OPENAI_API_KEY |
gpt-4o |
| Google Gemini | pip install 'cloudops-openkite[google]' |
GOOGLE_API_KEY |
gemini-2.0-flash |
| Mistral | pip install 'cloudops-openkite[mistral]' |
MISTRAL_API_KEY |
mistral-large-latest |
| Groq | pip install 'cloudops-openkite[groq]' |
GROQ_API_KEY |
llama-3.3-70b-versatile |
| Qwen (via DashScope) | pip install 'cloudops-openkite[qwen]' |
DASHSCOPE_API_KEY |
qwen3-coder-plus |
| OpenRouter | pip install 'cloudops-openkite[openai]' |
OPENROUTER_API_KEY |
anthropic/claude-haiku-4.5 |
| Ollama (local) | pip install 'cloudops-openkite[ollama]' |
none | llama3.1 |
Pick one block and export it (append to ~/.bashrc to make it sticky):
# OpenAI
export OPENKITE_PROVIDER=openai
export OPENKITE_MODEL=gpt-4o
export OPENAI_API_KEY=sk-...
# Google Gemini
export OPENKITE_PROVIDER=google
export OPENKITE_MODEL=gemini-2.0-flash
export GOOGLE_API_KEY=...
# Qwen via DashScope
export OPENKITE_PROVIDER=qwen
export OPENKITE_MODEL=qwen3-coder-plus
export DASHSCOPE_API_KEY=...
# Groq (Llama 3.3)
export OPENKITE_PROVIDER=groq
export OPENKITE_MODEL=llama-3.3-70b-versatile
export GROQ_API_KEY=...
# Ollama (local, no key)
export OPENKITE_PROVIDER=ollama
export OPENKITE_MODEL=llama3.1Or use the combined form and skip OPENKITE_PROVIDER:
export OPENKITE_MODEL=openai:gpt-4o
export OPENKITE_MODEL=anthropic:claude-sonnet-4-6Note on tool-calling fidelity — Claude (any tier), GPT-4o, Gemini 2.0 Pro, Qwen3-Coder, and Llama 3.3 70B all handle the 29-tool fan-out reliably. Smaller open models (Llama 3 8B, Mistral 7B) sometimes misroute on broad audits.
| Env var | Default | Purpose |
|---|---|---|
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY |
required | AWS credentials |
AWS_DEFAULT_REGION |
us-east-1 |
Default region for tools |
AWS_PROFILE |
— | Use a named profile from ~/.aws/credentials instead |
OPENKITE_PROVIDER |
anthropic |
LLM provider — see Choose your LLM provider |
OPENKITE_MODEL |
provider default | Model id, or combined provider:model form |
<PROVIDER>_API_KEY |
required | API key for the chosen provider (e.g. OPENAI_API_KEY) |
OPENKITE_DB |
checkpoints/openkite.db |
SQLite checkpoint path; unset for in-memory |
# run the test suite (23 tests, all moto-backed; no real AWS calls)
pytest -q
# lint
ruff check openkite tests
# install dev deps
pip install -e ".[dev]"The full test suite never hits real AWS or real Anthropic — moto fakes the AWS API and a FakeMessagesListChatModel scripts the LLM responses for ReAct flow tests.
openkite/
├── agent.py # build_agent() = create_react_agent(...)
├── llm.py # provider registry + build_llm() factory
├── cli.py # `openkite ask`, `openkite tools`, `openkite providers`
└── tools/
├── _aws.py # boto3 client factory + CW metric helpers + confirm()
├── ec2.py # EC2 / EBS / NAT / SG tools
├── rds.py # RDS tools
├── lambda_.py # Lambda tools
├── s3.py # S3 tools
└── cost.py # Cost Explorer tools
tests/
├── test_tools.py # moto-backed tool tests
└── test_agent.py # ReAct flow tests with fake LLM
The toolbox is the contract. To add a new capability:
- Pick a service file in
openkite/tools/(or create a new one and register it in__init__.py). - Add a
@tool-decorated function with typed args and a clear one-line docstring — the LLM picks tools by description. - Append it to the module's
*_TOOLSlist. - Write a moto test in
tests/test_tools.py. ruff check+pytest.
Composite analyzers should accept thresholds as parameters (e.g. cpu_threshold=5.0) so the LLM can pass arguments instead of getting hardcoded behaviour.
MIT — see LICENSE.
Built by Darshil. If OpenKite saves you a Sunday of cleanup, a star on GitHub is the best thank-you.
