Claude-code-plugins oraclecloud-local-dev-loop
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/oraclecloud-pack/skills/oraclecloud-local-dev-loop" ~/.claude/skills/jeremylongshore-claude-code-plugins-oraclecloud-local-dev-loop && rm -rf "$T"
plugins/saas-packs/oraclecloud-pack/skills/oraclecloud-local-dev-loop/SKILL.mdOracle Cloud Local Dev Loop
Overview
The OCI web console is slow, hard to navigate, and requires dozens of clicks for common operations. A local dev workflow using the OCI CLI and Python SDK replaces the console for everything: listing resources, launching instances, managing object storage, and checking service health. Profile switching lets you target dev/staging/prod from the same terminal.
Purpose: Set up a complete local OCI development environment with CLI profiles, shell aliases, environment variable management, and common workflow scripts that eliminate the need for the web console.
Prerequisites
- Completed
— validoraclecloud-install-auth
with at least one profile~/.oci/config - Python 3.8+ with
pip install oci oci-cli - Bash or Zsh shell
- OCIDs for your compartments (Governance > Compartments in the Console — last time you need it)
Instructions
Step 1: Install and Verify the OCI CLI
pip install oci-cli # Verify installation oci --version # Quick connectivity test oci iam region list --output table
Step 2: Set Up Multiple Profiles
Edit
~/.oci/config with profiles for each environment:
[DEFAULT] user=ocid1.user.oc1..aaaa_YOUR_USER fingerprint=ab:cd:ef:12:34:56:78:90:ab:cd:ef:12:34:56:78:90 tenancy=ocid1.tenancy.oc1..aaaa_PROD_TENANCY region=us-ashburn-1 key_file=~/.oci/oci_api_key.pem [dev] user=ocid1.user.oc1..aaaa_YOUR_USER fingerprint=ab:cd:ef:12:34:56:78:90:ab:cd:ef:12:34:56:78:90 tenancy=ocid1.tenancy.oc1..aaaa_DEV_TENANCY region=us-phoenix-1 key_file=~/.oci/oci_api_key_dev.pem [staging] user=ocid1.user.oc1..aaaa_YOUR_USER fingerprint=12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef tenancy=ocid1.tenancy.oc1..aaaa_STAGING_TENANCY region=eu-frankfurt-1 key_file=~/.oci/oci_api_key_staging.pem
Switch profiles with the
--profile flag or OCI_CLI_PROFILE env var:
# CLI flag oci compute instance list --compartment-id <OCID> --profile dev # Environment variable (applies to all commands in session) export OCI_CLI_PROFILE=dev oci compute instance list --compartment-id <OCID>
Step 3: Environment Variables and .env File
Create a project
.env file for compartment OCIDs and region defaults:
# .env — OCI project configuration (NEVER commit this file) OCI_COMPARTMENT_ID="ocid1.compartment.oc1..aaaa_YOUR_COMPARTMENT" OCI_TENANCY_ID="ocid1.tenancy.oc1..aaaa_YOUR_TENANCY" OCI_REGION="us-ashburn-1" OCI_CLI_PROFILE="DEFAULT"
# Add to .gitignore echo ".env" >> .gitignore # Source in your shell source .env
Step 4: Shell Aliases for Common Operations
Add these to your
~/.bashrc or ~/.zshrc:
# --- OCI Shell Aliases --- # Profile switching alias oci-dev='export OCI_CLI_PROFILE=dev && echo "Switched to dev"' alias oci-staging='export OCI_CLI_PROFILE=staging && echo "Switched to staging"' alias oci-prod='export OCI_CLI_PROFILE=DEFAULT && echo "Switched to prod"' # Compute alias oci-instances='oci compute instance list --compartment-id $OCI_COMPARTMENT_ID --output table --query "data[*].{Name:\"display-name\",State:\"lifecycle-state\",Shape:shape,OCID:id}"' alias oci-running='oci compute instance list --compartment-id $OCI_COMPARTMENT_ID --lifecycle-state RUNNING --output table' # Object Storage alias oci-buckets='oci os bucket list --compartment-id $OCI_COMPARTMENT_ID --output table --query "data[*].{Name:name,Created:\"time-created\"}"' # Networking alias oci-vcns='oci network vcn list --compartment-id $OCI_COMPARTMENT_ID --output table' alias oci-subnets='oci network subnet list --compartment-id $OCI_COMPARTMENT_ID --output table' # IAM alias oci-whoami='oci iam user get --user-id $(grep ^user ~/.oci/config | head -1 | cut -d= -f2) --query "data.{Name:name,Email:email}" --output table' # Health check alias oci-health='oci iam region list --output table && echo "OCI connectivity OK"'
Step 5: Common CLI Workflows
List and filter resources with JMESPath queries:
# Instances by shape oci compute instance list --compartment-id $OCI_COMPARTMENT_ID \ --query "data[?shape=='VM.Standard.A1.Flex'].{Name:\"display-name\",State:\"lifecycle-state\"}" \ --output table # Buckets with size (requires additional call per bucket) oci os bucket list --compartment-id $OCI_COMPARTMENT_ID \ --query "data[*].name" --raw-output # Find an image by name oci compute image list --compartment-id $OCI_COMPARTMENT_ID \ --query "data[?contains(\"display-name\", 'Oracle-Linux-8')].{Name:\"display-name\",ID:id}" \ --output table --limit 5
Instance lifecycle from CLI:
# Launch instance oci compute instance launch \ --compartment-id $OCI_COMPARTMENT_ID \ --availability-domain "Uocm:US-ASHBURN-AD-1" \ --shape "VM.Standard.E4.Flex" \ --shape-config '{"ocpus": 1, "memoryInGBs": 8}' \ --display-name "dev-instance" \ --image-id <IMAGE_OCID> \ --subnet-id <SUBNET_OCID> \ --ssh-authorized-keys-file ~/.ssh/id_rsa.pub # Stop / start / terminate oci compute instance action --instance-id <OCID> --action STOP oci compute instance action --instance-id <OCID> --action START oci compute instance terminate --instance-id <OCID> --force
Object storage operations:
# Upload a file oci os object put --bucket-name my-bucket --file ./data.csv --name data/input.csv # Download a file oci os object get --bucket-name my-bucket --name data/input.csv --file ./downloaded.csv # List objects with prefix oci os object list --bucket-name my-bucket --prefix "data/" \ --query "data[*].{Name:name,Size:size}" --output table # Bulk upload a directory oci os object bulk-upload --bucket-name my-bucket --src-dir ./upload/ --overwrite
Step 6: Python SDK Local Dev Script
Create a reusable dev helper:
#!/usr/bin/env python3 """oci_dev.py — Local OCI development helper.""" import oci import os import sys def get_config(profile="DEFAULT"): """Load OCI config with environment variable overrides.""" config = oci.config.from_file("~/.oci/config", profile_name=profile) # Allow env var override for compartment config["compartment_id"] = os.environ.get( "OCI_COMPARTMENT_ID", config.get("tenancy") ) oci.config.validate_config(config) return config def list_instances(config): compute = oci.core.ComputeClient(config, timeout=(10, 30)) instances = compute.list_instances( compartment_id=config["compartment_id"] ).data for inst in instances: print(f"{inst.display_name:<30} {inst.lifecycle_state:<12} {inst.shape}") return instances def list_buckets(config): os_client = oci.object_storage.ObjectStorageClient(config, timeout=(10, 30)) namespace = os_client.get_namespace().data buckets = os_client.list_buckets( namespace_name=namespace, compartment_id=config["compartment_id"] ).data for b in buckets: print(f"{b.name:<40} {b.time_created}") return buckets def health_check(config): identity = oci.identity.IdentityClient(config, timeout=(5, 15)) user = identity.get_user(config["user"]).data regions = identity.list_regions().data print(f"User: {user.name}") print(f"Regions: {len(regions)} available") print("Status: OK") if __name__ == "__main__": profile = os.environ.get("OCI_CLI_PROFILE", "DEFAULT") cfg = get_config(profile) cmd = sys.argv[1] if len(sys.argv) > 1 else "health" if cmd == "instances": list_instances(cfg) elif cmd == "buckets": list_buckets(cfg) elif cmd == "health": health_check(cfg) else: print(f"Usage: python oci_dev.py [instances|buckets|health]")
# Usage python oci_dev.py health python oci_dev.py instances OCI_CLI_PROFILE=dev python oci_dev.py buckets
Step 7: Project Structure
my-oci-project/ ├── .env # OCI_COMPARTMENT_ID, OCI_REGION, OCI_CLI_PROFILE ├── .gitignore # .env, *.pem, ~/.oci/ ├── oci_dev.py # Dev helper script (Step 6) ├── src/ │ └── oci_client.py # Singleton client (see oraclecloud-sdk-patterns) ├── scripts/ │ ├── setup.sh # Install oci + oci-cli + source .env │ └── teardown.sh # Terminate dev resources └── tests/ └── test_oci.py # Unit tests with mocked OCI responses
Output
Successful setup produces:
- OCI CLI installed and verified with
oci iam region list - Multi-profile
for dev/staging/prod switching~/.oci/config - Shell aliases for common OCI operations (instances, buckets, health)
- A reusable Python dev helper script for listing resources and health checks
- Environment variable management via
for project-specific OCIDs.env
Error Handling
| Error | Code | Cause | Solution |
|---|---|---|---|
| NotAuthenticated | 401 | Wrong profile or expired key | Check matches a valid config section |
| NotAuthorizedOrNotFound | 404 | Compartment OCID wrong for this profile | Verify matches the profile's tenancy |
| ConfigFileNotFound | — | missing | Run |
| command not found: oci | — | OCI CLI not installed | |
| TooManyRequests | 429 | Rapid CLI commands hitting rate limit | Add or space out requests |
| ServiceError status -1 | -1 | Network timeout | Check connectivity; increase timeout in SDK scripts |
Examples
One-liner resource summary:
echo "=== OCI Status ===" && \ oci-health && \ echo "Instances:" && oci-instances && \ echo "Buckets:" && oci-buckets
Switch profile and list resources in one command:
OCI_CLI_PROFILE=dev oci compute instance list \ --compartment-id $OCI_COMPARTMENT_ID --output table
Resources
- OCI CLI Reference — full command reference and configuration guide
- OCI CLI Configuration — config file format and profiles
- OCI Python SDK Reference — API documentation for all service clients
- OCI API Reference — REST API endpoints and schemas
- OCI Terraform Provider — infrastructure as code alternative
- OCI Status — service health dashboard
Next Steps
With your local dev loop set up, see
oraclecloud-sdk-patterns for production-grade client patterns, or oraclecloud-common-errors when you hit issues during development.