
Cloud Manage Project
Manage Elastic Cloud Serverless projects—list, update, rotate credentials, and delete—from your agent without clicking the Elastic console.
Overview
cloud-manage-project is an agent skill most often used in Operate (also Build integrations) that documents CLI commands to list, update, reset credentials, and delete Elastic Cloud Serverless projects.
Install
npx skills add https://github.com/elastic/agent-skills --skill cloud-manage-projectWhat is this skill?
- Python CLI with list, get, update, reset-credentials, and delete against the Serverless REST API
- Documents `.elastic-credentials` sections (project headers, URLs, admin password, API keys)
- `load-credentials` merges sections; admin username/password export only with `--include-admin`
- Supports updating name, alias, tags, and search_lake settings on existing projects
- Designed to pair with create-project flows for full Elastic Cloud Serverless workflows
- Five documented commands: list, get, update, reset-credentials, delete
Adoption & trust: 949 installs on skills.sh; 502 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have Elastic Serverless projects running but no scripted, agent-friendly way to inspect them, rotate secrets, or tear them down consistently.
Who is it for?
Solo builders automating Elastic Cloud Serverless with agent skills who need credential hygiene and project lifecycle commands in-repo.
Skip if: Teams only using self-managed Elastic on VMs or Kubernetes without the Serverless REST API and credential file workflow.
When should I use this skill?
You already use Elastic Cloud Serverless and need to list, update, reset-credentials, or delete projects via the documented Python CLI and credential file.
What do I get? / Deliverables
Your agent runs documented manage-project commands and keeps `.elastic-credentials` aligned so downstream Elastic skills can load URLs and API keys safely.
- Updated `.elastic-credentials` sections
- Project metadata changes via API
- Rotated or removed project credentials
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Lifecycle management of hosted Elasticsearch/Kibana projects is production and platform operations, so Operate → Infra is the canonical shelf. Commands target cloud project CRUD, credential resets, and API keys—core infra stewardship, not app feature coding.
Where it fits
Reload merged credentials after your agent updates project tags before indexing a new data source.
Verify project URLs and keys right before a production cutover to Elastic Serverless.
Rotate admin credentials and append a fresh API key section without manual Kibana clicks.
How it compares
Operational runbook for Elastic Serverless projects—not a generic Terraform or Pulumi IaC module.
Common Questions / FAQ
Who is cloud-manage-project for?
Indie and solo developers using Elastic’s agent-skills stack to run Elasticsearch/Kibana Serverless and wanting terminal-driven project admin.
When should I use cloud-manage-project?
During Operate when rotating credentials, auditing projects, or decommissioning stacks; during Build when wiring integrations that depend on merged `.elastic-credentials`.
Is cloud-manage-project safe to install?
It describes admin passwords and API keys on disk—review the Security Audits panel on this page and restrict `--include-admin` to short-lived key creation only.
SKILL.md
READMESKILL.md - Cloud Manage Project
# Credential file format Each section in `.elastic-credentials` starts with a header containing the **project name** and **project ID**. The `load-credentials` command uses these headers to retrieve credentials for a specific project. **Project section** (written automatically by `create-project` and `reset-credentials`): ```text # Project: <project-name> | id=<project-id> | <timestamp> ELASTICSEARCH_URL=https://... KIBANA_URL=https://... ELASTICSEARCH_USERNAME=admin ELASTICSEARCH_PASSWORD=<password> ``` **API key section** (append when creating Elasticsearch API keys): ```text # API Key: <key-name> | project=<project-name> | id=<project-id> | <details> ELASTICSEARCH_API_KEY=<base64-encoded-key> ``` Sections for the same project are merged by `load-credentials`. Later entries overwrite earlier ones. `ELASTICSEARCH_USERNAME` and `ELASTICSEARCH_PASSWORD` are saved to the file but **not exported** by `load-credentials` unless `--include-admin` is passed. Use `--include-admin` only when creating an API key, then reload without it. #!/usr/bin/env python3 """Manage existing Elastic Cloud Serverless projects via the Serverless REST API. Usage: python3 manage-project.py <command> [options] Commands: list List projects of a given type get Get project details update Update project name, alias, tags, or search_lake settings reset-credentials Reset project credentials delete Delete a project resume Resume a suspended project load-credentials Load project credentials from .elastic-credentials Commands that call the Cloud API require the EC_API_KEY environment variable. """ import argparse import copy import json import os import re import shlex import sys import time import urllib.error import urllib.request from datetime import datetime, timezone def load_dotenv(path=".env"): """Load KEY=VALUE pairs from a .env file into os.environ (no overwrite).""" try: with open(path) as f: for line in f: line = line.strip() if not line or line.startswith("#") or "=" not in line: continue key, _, value = line.partition("=") os.environ.setdefault(key.strip(), value.strip().strip("'\"")) except FileNotFoundError: pass load_dotenv() BASE_URL = os.environ.get("EC_BASE_URL", "https://api.elastic-cloud.com") API_PREFIX = "/api/v1/serverless" VALID_TYPES = ("elasticsearch", "observability", "security") def get_api_key(): key = os.environ.get("EC_API_KEY") if not key: print("Error: EC_API_KEY environment variable is not set.", file=sys.stderr) print("Run the cloud-setup skill to configure authentication.", file=sys.stderr) sys.exit(1) return key def api_request(method, path, body=None): url = f"{BASE_URL}{API_PREFIX}{path}" headers = { "Authorization": f"ApiKey {get_api_key()}", "Content-Type": "application/json", "User-Agent": "elastic-agentic", } data = json.dumps(body).encode() if body else None req = urllib.request.Request(url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=30) as resp: raw = resp.read().decode() return json.loads(raw) if raw else {} except urllib.error.HTTPError as e: error_body = e.read().decode() try: error_json = json.loads(error_body) print(json.dumps(error_json, indent=2), file=sys.stderr) except json.JSONDecodeError: print(error_body, file=sys.stderr) print(f"\nHTTP {e.code}: {e.reason}", file=sys.stderr) sys.exit(1) except urllib.error.URLError as e: print(f"Error: unable to reach {url}: {e.reason}", file=sys.stderr) sys.exit(1) def cmd_list(args): result = api_request("GET", f"/projects/{args.type}") items = result.get("