npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@leettools/leet-deploy

v0.1.1

Published

Deploy applications to Kubernetes clusters or cloud VM instances

Readme

leet-deploy

A full-stack tool for deploying applications to Kubernetes clusters and cloud VM instances — a Python backend (CLI + FastAPI service) paired with a Vue web UI.

What's in this Repository

| Path | What it is | | --------------------------------------------- | ------------------------------------------------------------------------------------------- | | leet_deploy/ | Python package — CLI, FastAPI service, and Python API. See its README for full details. | | leet_deploy_web/ | Vue 3 web UI that talks to the FastAPI service. | | examples/ | Sample deploy.yaml files and VM configs. | | skills/ | LLM-harness skills (spec-finder, purchase-spec, deploy-app, deploy-dockerfile-edge) that drive the CLI. | | docs/ | Marketing and tutorial material for explaining the product workflow. | | development/ | Developer notes and scratch material. |

What It Does

  • Create Kubernetes clusters on AWS (EKS) or GCP (GKE) with a single command
  • Deploy applications to Kubernetes from a deploy.yaml file (local, GitHub, or HTTP URL)
  • Launch cloud VMs with Docker containers on AWS EC2, GCP Compute Engine, or Aliyun ECS
  • Publish VM apps through HTTPS edge stacks on GCP or Aliyun
  • Ship local apps (compose file + locally-built images) to a VM over SSH — no registry required
  • Manage deployments with status, rollback, and delete commands
  • Drive everything from the browser via the Vue web UI, or from the CLI / HTTP API

Architecture

  +-----------------+       HTTP        +------------------------+       Helm / Cloud APIs        +--------------------+
  |  Vue Web UI     | <---------------> |  FastAPI service       | ----------------------------> |  Kubernetes / VMs  |
  | leet_deploy_web |                   |  leet_deploy (Python)  |                                | (EKS / GKE / EC2 / ECS) |
  +-----------------+                   +-----------+------------+                                +--------------------+
                                                    ^
                                                    |
                                             CLI (leet-deploy)
                                             Python API

Everything the UI does ultimately goes through the Python package's FastAPI service, which in turn uses Helm and cloud provider APIs.

Prerequisites

  • Python >= 3.11 (a conda environment named deploy is recommended)
  • Node.js v20.19.0 (via nvm) for the web UI
  • Helm 3.x installed and in PATH
  • kubectl configured with access to target cluster(s)
  • Cloud credentials (AWS, GCP, and/or Aliyun) if you plan to use those providers

See leet_deploy/README.md for the exact environment variables.

Required Cloud Privileges

Grant the identity running leet-deploy at least the privileges below. Each capability is separable — e.g., you can skip the pricing rows if you only need catalog-refresh --skip-prices, or the EKS/GKE rows if you only launch standalone VMs.

GCP

Credentials:

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
export GOOGLE_CLOUD_PROJECT=<project-id>

Enable these APIs on the project (gcloud services enable <name>):

  • compute.googleapis.com — Compute Engine (VMs, firewalls, zones)
  • container.googleapis.com — Kubernetes Engine (GKE clusters)
  • cloudbilling.googleapis.com — Cloud Billing Catalog (instance prices)

Grant these roles to the service account:

| Capability | Role(s) | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | VM create/terminate + firewall rules (instance-deploy) | roles/compute.admin (or roles/compute.instanceAdmin.v1 + roles/compute.securityAdmin) | | VM + global HTTPS load balancer + self-managed SSL (deploy-dockerfile-edge) | roles/compute.admin, or an equivalent custom role covering instances, firewalls, global addresses, backend services, health checks, URL maps, target HTTPS proxies, forwarding rules, zonal NEGs, and SSL certificates | | VM + catalog read (cloud-discover, instance-status, catalog-refresh --skip-prices) | roles/compute.viewer | | GKE cluster create/delete (cluster-create / cluster-delete) | roles/container.admin, plus roles/iam.serviceAccountUser on the node service account | | Instance prices (catalog-refresh without --skip-prices) | roles/billing.viewer |

The service-account key must live in the same project as GOOGLE_CLOUD_PROJECT — a key owned by a different project will work for auth but the Cloud Billing Catalog then 403s against the key's home project rather than the workload project.

The deploy-dockerfile-edge flow also requires GoDaddy API credentials (GODADDY_API_KEY, GODADDY_API_SECRET) and an ACME account email in LEET_DEPLOY_EDGE_TLS_EMAIL.

AWS

Credentials:

export AWS_ACCESS_KEY_ID=<your-key>
export AWS_SECRET_ACCESS_KEY=<your-secret>
export AWS_DEFAULT_REGION=us-west-2

Grant these IAM actions to the principal:

| Capability | IAM actions | | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | VM instances (instance-deploy, instance-status, instance-cleanup, cloud-discover) | ec2:DescribeRegions, ec2:DescribeInstances, ec2:RunInstances, ec2:TerminateInstances, ec2:CreateTags, ec2:DescribeKeyPairs, ec2:ImportKeyPair, ec2:DescribeSecurityGroups, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress | | EKS clusters (cluster-create / cluster-delete) | eks:CreateCluster, eks:DescribeCluster, eks:ListClusters, eks:DeleteCluster, eks:CreateNodegroup, eks:DeleteNodegroup; plus iam:CreateRole, iam:GetRole, iam:AttachRolePolicy, iam:ListAttachedRolePolicies, iam:PassRole for the EKS service & node roles | | --auto-vpc flag on cluster-create | ec2:CreateVpc, ec2:DescribeVpcs, ec2:ModifyVpcAttribute, ec2:DeleteVpc, ec2:CreateSubnet, ec2:DescribeSubnets, ec2:ModifySubnetAttribute, ec2:DeleteSubnet, ec2:CreateInternetGateway, ec2:DescribeInternetGateways, ec2:AttachInternetGateway, ec2:DetachInternetGateway, ec2:DeleteInternetGateway, ec2:CreateRouteTable, ec2:DescribeRouteTables, ec2:AssociateRouteTable, ec2:DisassociateRouteTable, ec2:CreateRoute, ec2:DeleteRouteTable, ec2:DescribeAvailabilityZones | | Catalog refresh (catalog-refresh --provider aws [--skip-prices]) | ec2:DescribeRegions, ec2:DescribeInstanceTypes, ec2:DescribeInstanceTypeOfferings | | On-demand prices (catalog-refresh without --skip-prices) | pricing:GetProducts, pricing:DescribeServices (the Pricing API is only served from us-east-1, ap-south-1, eu-central-1 — leet-deploy pins to us-east-1) | | Spot prices (catalog-refresh --pricing-model spot) | ec2:DescribeSpotPriceHistory |

If you prefer AWS-managed policies over a custom one, the superset AmazonEC2FullAccess + AWSPriceListServiceFullAccess covers the VM + catalog + pricing rows. EKS also needs the cluster to assume AmazonEKSClusterPolicy and worker nodes AmazonEKSWorkerNodePolicy + AmazonEC2ContainerRegistryReadOnly + AmazonEKS_CNI_Policy — leet-deploy creates and attaches these automatically when given the iam:* actions above.

Aliyun

Credentials:

export ALIBABA_CLOUD_ACCESS_KEY_ID=<your-access-key-id>
export ALIBABA_CLOUD_ACCESS_KEY_SECRET=<your-access-key-secret>
export ALIBABA_CLOUD_REGION_ID=cn-hangzhou

The Alibaba Cloud SDK credential chain can also read ~/.aliyun/config.json. The ALIBABA_CLOUD_REGION_ID value is optional for commands that pass --region, but it is useful for certificate DNS-01 operations.

Grant these RAM actions to the principal:

| Capability | RAM actions | | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | VM discovery/status (cloud-discover, instance-status) | ecs:DescribeRegions, ecs:DescribeInstances | | VM create/delete (instance-deploy, instance-cleanup) | ecs:RunInstances, ecs:DeleteInstance, ecs:DescribeImages, ecs:DescribeInstances, ecs:DescribeKeyPairs, ecs:ImportKeyPair, ecs:DescribeSecurityGroups, ecs:CreateSecurityGroup, ecs:AuthorizeSecurityGroup | | VPC/VSwitch creation for ECS | vpc:DescribeVpcs, vpc:CreateVpc, vpc:DescribeVSwitches, vpc:CreateVSwitch | | Catalog and pricing (catalog-refresh --provider aliyun) | ecs:DescribeRegions, ecs:DescribeInstanceTypes, ecs:DescribePrice | | Aliyun HTTPS edge stack (ECS VM + CLB/SLB + AliDNS) | The VM and VPC actions above, plus slb:CreateLoadBalancer, slb:DescribeLoadBalancers, slb:DescribeLoadBalancerAttribute, slb:AddBackendServers, slb:RemoveBackendServers, slb:CreateLoadBalancerHTTPSListener, slb:StartLoadBalancerListener, slb:UploadServerCertificate, slb:DescribeServerCertificates, alidns:DescribeDomains, alidns:DescribeDomainRecords, alidns:AddDomainRecord, alidns:UpdateDomainRecord, alidns:DeleteDomainRecord |

If you prefer broad managed policies while testing, AliyunECSFullAccess, AliyunVPCFullAccess, AliyunSLBFullAccess, and AliyunDNSFullAccess cover the VM plus Aliyun edge path. cluster-create and cluster-delete currently reject --provider aliyun; ACK orchestration is not implemented yet.

See docs/aliyun-edge-tutorial.md for an end-to-end ECS + CLB + AliDNS HTTPS walkthrough.

Running the Full Stack

1. Backend (FastAPI service)

From the repo root:

# Install with all cloud providers (pick [aws], [gcp], [aliyun], or omit for core-only)
conda run -n deploy pip install -e ".[cloud]"

# Start the API service
conda run -n deploy leet-deploy-service --host 0.0.0.0 --port 8000

The API is available at http://localhost:8000 with interactive docs at http://localhost:8000/docs.

For CLI usage, default-cluster bootstrap, full HTTP API reference, deploy.yaml formats, and the Python API, see leet_deploy/README.md.

2. Frontend (Vue web UI)

From the repo root:

cd leet_deploy_web

# Copy the env template and configure the API URL
cp .env.example .env
# Defaults: VITE_API_BASE=http://localhost:8000, VITE_FRONTEND_PORT=5173

# Install dependencies and start the dev server (hot reload)
npm install
npm run dev

The UI is available at http://localhost:5173. The API base URL can also be changed at runtime from the Settings page.

3. Production build of the UI

cd leet_deploy_web
npm run build       # outputs to leet_deploy_web/dist
npm run preview     # optional: serve the built assets locally

Quick Start (CLI only)

If you only want the CLI — no UI, no service — install the Python package and go:

pip install -e ".[cloud]"

# Create a cluster and deploy
leet-deploy cluster-create --provider aws --name my-cluster --region us-west-2 --nodes 2 --auto-vpc
leet-deploy deploy ./deploy.yaml --target aws:eks:my-cluster

Full CLI reference: leet_deploy/README.md#cli-reference.

Using with an LLM Harness (Skills)

The skills/ directory ships four Anthropic-style agent skills that let a harness (Claude Code, the Claude API with skill loading, Claude Desktop with MCP, etc.) drive leet-deploy from natural-language prompts. The skills are plain Markdown — no in-repo LLM client is required; the harness does the model calls, the skills tell it which CLI invocations to produce.

| Skill | Purpose | | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | | skills/spec-finder/ | Turn "cheapest GCP VM for a daemon" into a concrete instance type by filtering the local catalog + prices. | | skills/purchase-spec/ | Provision a VM at a chosen spec with no app running (idle box for later SSH / custom setup). | | skills/deploy-app/ | Provision a VM at a chosen spec and run a Docker image on it, in one CLI call. | | skills/deploy-dockerfile-edge/ | Build a local Dockerfile, ship it to a fresh GCP VM, then wire GCP HTTPS load balancing, TLS, and GoDaddy DNS cutover. |

Typical end-to-end flow:

user:  "cheapest GCP VM in us-central1 to run my image acme/hello:1.0"

  ├── spec-finder      → calls `leet-deploy catalog-query` → picks e2-small
  └── deploy-app       → calls `leet-deploy instance-deploy
                              --provider gcp --region us-central1
                              --cpu 2 --memory 2
                              --image acme/hello:1.0 --wait`
                       ← returns public IP + cleanup command

spec-finder only picks; purchase-spec and deploy-app are the two ways to act on that pick. purchase-spec never deploys an app, and deploy-app does both provisioning and deployment in the same step — you do not need to run purchase-spec first.

deploy-dockerfile-edge is the path for "I have a local Dockerfile and a GoDaddy domain" workflows. It runs a staged preflight first, then builds the Dockerfile locally, deploys a GCP VM, ships the image over SSH, creates the HTTPS load balancer, issues the certificate, and updates GoDaddy DNS.

For an Aliyun-only ECS + CLB + AliDNS edge deployment, use leet-deploy instance-deploy --config with an edge VM config. See docs/aliyun-edge-tutorial.md.

Loading the skills

  • Claude Code: copy (or symlink) skills/<name>/ into ~/.claude/skills/ or your project's .claude/skills/. The harness will auto-match SKILL.md description against user prompts.
  • Claude API (skill loading): point your skill-loader at the skills/ directory; each subfolder is one skill.
  • Other harnesses: any tool that understands the SKILL.md + frontmatter convention can consume these directly.

Before the skills can recommend an instance, the catalog must be populated once per provider/region:

leet-deploy catalog-refresh --provider gcp --region us-central1
leet-deploy catalog-refresh --provider aws --region us-west-2
leet-deploy catalog-refresh --provider aliyun --region cn-hangzhou

The skills expect cloud credentials to be configured the same way the CLI does — see Required Cloud Privileges. They run leet-deploy connection-check as a preflight, so broken credentials surface before any VM is launched.

For deploy-dockerfile-edge, also set:

export GODADDY_API_KEY=<godaddy-key>
export GODADDY_API_SECRET=<godaddy-secret>
export LEET_DEPLOY_EDGE_TLS_EMAIL=<[email protected]>

Optional overrides for that skill:

export LEET_DEPLOY_EDGE_ZONE=example.com          # needed when deploying a subdomain
export LEET_DEPLOY_EDGE_REGION=us-central1
export LEET_DEPLOY_EDGE_CPU=2
export LEET_DEPLOY_EDGE_MEMORY_GIB=4

Run the helper in preflight mode first:

conda run -n deploy python -m leet_deploy.edge.dockerfile_workflow \
  --dockerfile examples/web_server/Dockerfile \
  --domain xxx.com \
  --preflight-only

Then run the real deploy:

conda run -n deploy python -m leet_deploy.edge.dockerfile_workflow \
  --dockerfile examples/web_server/Dockerfile \
  --domain xxx.com

Preparing an app for deploy-app

leet-deploy instance-deploy --image <ref> (which deploy-app invokes) boots an Ubuntu 22.04 VM, installs Docker via cloud-init, then runs:

docker pull <image>
docker run -d --name app -p 8080:8080 <image>

Port 8080 is the only port opened on the VM's firewall / security group. So, for an image to work with deploy-app, it must:

  1. Be hosted on a publicly pullable registry (Docker Hub public, GHCR public, a public ECR/Artifact Registry repo). The VM has no registry credentials by default — private images will fail at docker pull. If you need a private registry, use the config-file form of instance-deploy with a custom cloudInit: that runs docker login before the pull.
  2. Listen on 0.0.0.0:8080 inside the container. Apps hard-coded to 127.0.0.1 or any other port won't be reachable on http://<public_ip>:8080. Map the port inside your Dockerfile (EXPOSE 8080) and bind your server accordingly.
  3. Be linux/amd64 unless you picked an ARM spec. The AWS Graviton and GCP Tau/Axion families are arm64; everything else in the catalog is x86_64. Build multi-arch images (docker buildx build --platform linux/amd64,linux/arm64 …) or match the image arch to the spec you chose.
  4. Start a long-running process in the foreground. The container is launched -d with no restart policy — if the process exits, the container stops and the app goes dark. Use an entrypoint that stays up (uvicorn, node, nginx -g 'daemon off;', etc.).

A minimal Dockerfile that satisfies all four:

FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]

Push it to a public registry, then hand the image reference to the deploy-app skill (or to leet-deploy instance-deploy --image … directly). For anything more complex — multiple ports, env vars, volume mounts, private registries, custom OS image — use the config-file form with a full vm-config-*.yaml (see examples/vm-config-aws.yaml, examples/vm-config-gcp.yaml).

With the default --wait, the CLI does not return as soon as the VM gets an IP. It now waits for SSH, the Docker daemon, the app container, and an HTTP response from http://<public_ip>:8080.

For apps that need local secret files at deploy time, instance-deploy also supports repeatable --secret <local_path>=<container_path> mounts and a numeric --container-user override. When secrets are configured, leet-deploy waits for the VM to boot, uploads the local secret tree to /var/lib/leet-deploy/secrets/<instance-id>, tightens it to owner-only permissions, and starts the container with read-only bind mounts. The config-file form accepts the same settings under:

container:
  user: "1000:1000"
  secrets:
    - source: "./secrets/prod.env"
      target: "/run/secrets/app.env"

Shipping a Local App (no registry)

When the app isn't published to a registry — a local build, a private image, a quick iteration — use leet-deploy app-ship to push a docker-compose.yml plus any locally-built images to an existing VM and start them with docker compose up -d.

# 1. Build + tag locally (no push required):
docker build -t my-app:local ./app

# 2. Provision a VM once (idle):
leet-deploy instance-deploy --provider gcp --region us-central1 \
  --name my-vm --cpu 2 --memory 4 --wait

# 3. Ship the compose app to it:
leet-deploy app-ship \
  --compose examples/docker-compose-local.yml \
  --instance-id <id> --provider gcp --region us-central1 \
  --ssh-key ~/.ssh/id_rsa

What happens:

  1. Parses the compose file and lists its images.
  2. For each image that exists locally, streams it to the VM over SSH into docker load on the remote. Images not present locally (e.g. redis:7-alpine) are left for the remote docker compose to pull.
  3. Uploads a build:-stripped copy of docker-compose.yml to the VM (default /opt/app/docker-compose.yml).
  4. Runs docker compose up -d on the VM and returns docker compose ps.

Key properties:

  • No docker CLI on the local host. Images are read via the Docker Engine API (docker-py), so leet-deploy can run inside a container with the host socket mounted (-v /var/run/docker.sock:/var/run/docker.sock).
  • No registry push. Nothing leaves your machine except over the SSH connection to the target VM.
  • Services without an image: tag fail fast. Compose services that only have a build: block are rejected — app-ship never builds; tag the image locally (docker build -t name:tag) and add image: name:tag in the compose file.
  • Targeting. Use --instance-id/--provider/--region to resolve the VM's public IP via the cloud provider, or pass --host <ip> directly.

Install the extra deps:

pip install -e ".[app-ship]"   # adds docker-py and paramiko

See examples/docker-compose-local.yml for a minimal starting point.

Development

Backend:

conda run -n deploy pip install -e ".[dev]"
conda run -n deploy pytest
conda run -n deploy mypy leet_deploy
conda run -n deploy ruff check leet_deploy

Frontend:

cd leet_deploy_web
npm install
npm run dev

License

MIT