New Claude Code Skills

New Claude Code Skills


  Overall there are 3 skills: Lightsail, Docker and Powershell. You need to put these skills into the user-level C:\Users\ericw\.claude\skills\ directory. Remember that there be a folder with the skill name and inside it will be skill.md and an optional reference.md .

==============================================

Lightsail Skill.Md:

---
name: aws-lightsail-container-deploy
description: Hard-won operational knowledge for deploying multi-container apps to AWS Lightsail Container Service — container naming rules, image versioning, the real create-container-service-deployment API shape, pod-style shared networking, the deployment state model, and log-based debugging. Use when running `aws lightsail` container-service commands, deploying or redeploying to Lightsail, editing a Lightsail containers.json/public-endpoint.json, or debugging a Lightsail container-service error.
---
# AWS Lightsail Container Service Deploy
Load this before writing any `aws lightsail` container-service command or touching `containers.json` — the API and runtime model here diverge from both plain ECS and Docker Compose in ways that produce confusing errors if you guess.
## Quick start — the correct deploy sequence
```bash
# 1. Get the CURRENT highest version for every image — never assume/increment manually, never use ":latest"
aws lightsail get-container-images --service-name <service> --query "containerImages[].image"
# 2. Push a new image, note the printed version it lands on
aws lightsail push-container-image --service-name <service> --label <label> --image <local-image>:local
# 3. Update containers.json with the new numeric version for the image(s) that changed
# 4. Deploy — containers and publicEndpoint are SEPARATE flags, not one --cli-input-json payload
aws lightsail create-container-service-deployment \
  --service-name <service> \
  --containers file://containers.json \
  --public-endpoint file://public-endpoint.json
# 5. Poll the DEPLOYMENT state (not the service state) until ACTIVE
aws lightsail get-container-services --service-name <service> \
  --query "containerServices[0].currentDeployment.{version:version,state:state}"
# 6. On failure, pull real logs per-container rather than guessing
aws lightsail get-container-log --service-name <service> --container-name <name> --query "logEvents[-20:]"
```
## Core rules
1. **Container names**: hyphens only, no underscores — must match `^(?:[a-z0-9]{1,2}|[a-z0-9][a-z0-9-]+[a-z0-9])$`.
2. **Image versions are numeric-only** — there is no `:latest`/`.LATEST`. Always re-check `get-container-images` right before deploying.
3. **`create-container-service-deployment` takes `--containers file://...` and `--public-endpoint file://...`** as separate parameters — never `--cli-input-json` with the container map as the whole payload.
4. **No per-container DNS.** All containers in one deployment share a single network namespace (pod-style). Reach a sibling via `localhost:<port>`, never its container name — that only works in Docker Compose.
5. **Only one container per deployment can be public** (`publicEndpoint`). Multiple logically-public services (SPA + API) need a reverse-proxy container (nginx) as the sole public endpoint, routing internally over `localhost`. Side effect: same-origin, so no CORS needed.
6. **No `depends_on` equivalent** — containers start in parallel with no ordering guarantee. Anything that resolves a sibling hostname at startup (e.g. nginx `proxy_pass`) needs lazy/per-request resolution, not a literal target, or it can crash before a sibling is even up.
7. **Two different `state` fields**: the container *service's* state (`READY` — there is no "RUNNING") vs. an individual *deployment's* state (`ACTIVATING` → `ACTIVE`/`FAILED`, superseded ones go `INACTIVE`). `ACTIVATING` can legitimately sit for several minutes.
8. **No IaC path fits this well** — it's CLI-managed (`push-container-image` + `create-container-service-deployment`), not Terraform/CloudFormation-first for a small service like this.
9. **Secrets live in plain env vars inside `containers.json`** — there's no secrets-manager integration at this tier. Gitignore the real file; keep a redacted `.example` sibling checked in for shape.
Full symptom → cause → fix detail (exact error text as actually seen) for every rule above: see [REFERENCE.md](REFERENCE.md).

Lightsail Reference.Md:
# AWS Lightsail Container Service — Gotcha Reference

Each entry: the symptom as actually seen, why it happens, and the fix. All verified firsthand (Critical Viewer project, a 3-container .NET/React app: nginx proxy + ASP.NET backend + React frontend on Lightsail Container Service, `nano` power, `us-east-2`).

## 1. Container naming — underscores are rejected

**Symptom:**
```
An error occurred (InvalidInputException) when calling the CreateContainerServiceDeployment operation:
Container name "backend_api" does not match pattern: ^(?:[a-z0-9]{1,2}|[a-z0-9][a-z0-9-]+[a-z0-9])$
```

**Cause:** Lightsail container names allow lowercase alphanumerics and hyphens only — no underscores, unlike a lot of Docker-world naming conventions.

**Fix:** Use hyphens everywhere a container is named — `backend-api`, `frontend-ui`, not `backend_api`/`frontend_ui`. Keep this consistent with `containers.json` keys and any Dockerfile/compose service names you want to visually match.

## 2. Image versions are numeric-only

**Symptom:**
```
An error occurred (InvalidInputException) when calling the CreateContainerServiceDeployment operation:
Container "frontend-ui" has invalid image ":container-service-1.my-react-ui.LATEST".
Example of valid image: ":container-service-1.frontend-ui.123".
```

**Cause:** There is no `:latest`/`.LATEST` moving tag for Lightsail container images — only literal, monotonically-increasing integers per label, assigned by `push-container-image`.

**Fix:** Before every deployment, run:
```bash
aws lightsail get-container-images --service-name <service> --query "containerImages[].image"
```
and read off the actual current highest version per label. Never hardcode "latest" and never manually increment a remembered number — old versions can be deleted independently, so the true current version isn't always "last one you pushed + 1".

## 3. `create-container-service-deployment` payload shape

**Symptom:**
```
An error occurred (ParamValidation): Parameter validation failed:
Unknown parameter in input: "proxy", must be one of: serviceName, containers, publicEndpoint
Unknown parameter in input: "backend-api", must be one of: serviceName, containers, publicEndpoint
Unknown parameter in input: "frontend-ui", must be one of: serviceName, containers, publicEndpoint
```

**Cause:** This happens from running:
```bash
aws lightsail create-container-service-deployment --service-name <service> --cli-input-json file://containers.json
```
`--cli-input-json` expects the *entire* request payload — `{serviceName, containers, publicEndpoint}` — but a typical `containers.json` (as most guides and this project's own `deploy/lightsail/containers.json` are written) is just the container-name → container-spec map, which is only the *value* of the `containers` parameter, not the whole request.

**Fix:** Pass `--containers` and `--public-endpoint` as their own flags, each pointed at its own file:
```bash
aws lightsail create-container-service-deployment \
  --service-name <service> \
  --containers file://deploy/lightsail/containers.json \
  --public-endpoint file://deploy/lightsail/public-endpoint.json
```
where `public-endpoint.json` looks like:
```json
{
  "containerName": "proxy",
  "containerPort": 80,
  "healthCheck": {
    "path": "/api/health",
    "successCodes": "200",
    "intervalSeconds": 10,
    "timeoutSeconds": 5,
    "healthyThreshold": 2,
    "unhealthyThreshold": 5
  }
}
```

## 4. Pod-style shared networking — no per-container DNS

**Symptom (from a proxy container's logs):**
```
[error] 38#38: *9 backend-api could not be resolved (3: Host not found), client: ..., request: "GET /api/health HTTP/1.1", ...
```
paired with `502` responses at the public endpoint.

**Cause:** Docker Compose gives every service its own per-service DNS name on a shared bridge network (`backend-api` resolves from `proxy`). Lightsail Container Service does **not** work this way — every container in one deployment runs inside a single shared network namespace, pod-style. There is no per-container DNS name at all.

**Fix:** Address sibling containers via `localhost:<port>`, not their container name. If the same config needs to work in both Docker Compose (local) and Lightsail (real), parameterize the upstream host via an environment variable rather than hardcoding either value:
- Compose: `BACKEND_API_UPSTREAM=backend-api:8080`
- Lightsail: `BACKEND_API_UPSTREAM=localhost:8080`

## 5. Only one container can be public

**Symptom:** No error exactly — it's a design constraint. `publicEndpoint` accepts exactly one `containerName`.

**Cause:** Lightsail Container Service allows exactly one publicly-reachable container per deployment. An app shaped as "SPA calls a separate API" doesn't fit that directly.

**Fix:** Add a reverse-proxy container (nginx is the natural choice) as the sole public container, routing internally by path (`/api/*` → backend, everything else → frontend) over `localhost`. Bonus: this makes frontend and API same-origin from the browser's perspective, so CORS isn't needed for real traffic.

## 6. No `depends_on` — containers start in parallel

**Symptom:** A proxy container crashes outright at boot (not just individual requests failing) if `proxy_pass` targets a literal hostname that isn't resolvable yet.

**Cause:** Lightsail has no equivalent of Compose's `depends_on` to sequence container startup. All containers in a deployment start in parallel with no ordering guarantee.

**Fix (nginx-specific pattern that held up):** Use a `resolver` directive plus a `set`-based indirection so nginx resolves the upstream lazily, per-request, instead of once at startup:
```nginx
resolver ${NGINX_LOCAL_RESOLVERS} valid=10s;

location /api/ {
    set $backend_api ${BACKEND_API_UPSTREAM};
    proxy_pass http://$backend_api;
    ...
}
```
A bare literal `proxy_pass http://backend-api:8080;` fails hard at startup if resolution fails even once; the `set $var; proxy_pass http://$var;` form doesn't. `${NGINX_LOCAL_RESOLVERS}` comes from the official nginx image's own `15-local-resolvers.envsh` entrypoint step (reads `/etc/resolv.conf`), gated behind `NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1` on the container — without that env var the script silently no-ops and the template substitution never happens.

## 7. Two different `state` fields

**Symptom:** Confusion between `"state": "READY"` on the service and `"state": "ACTIVATING"`/`"ACTIVE"`/`"FAILED"`/`"INACTIVE"` on deployments — there is no `"RUNNING"` state anywhere in this API, despite it being an intuitive guess.

**Cause:** `get-container-services` returns the container *service's* own state (`READY` when the service itself is up and serving *some* deployment) separately from `currentDeployment.state` / `nextDeployment.state`, which track the specific deployment version's rollout.

**Fix:** When waiting for a new deploy to take effect, poll the *deployment* state, not the service state:
```bash
aws lightsail get-container-services --service-name <service> \
  --query "containerServices[0].currentDeployment.{version:version,state:state}"
```
Expect `ACTIVATING` to persist for several minutes — that's normal, not stuck. A superseded previous deployment shows `INACTIVE` once the new one goes `ACTIVE`.

## 8. Debugging a failed/unhealthy deployment

**Command:**
```bash
aws lightsail get-container-log --service-name <service> --container-name <name> --query "logEvents[-20:]"
```

**Signatures actually seen and what they meant:**
- `"[deployment:4] Took too long"` in the app container's own logs — the app didn't bind/respond inside the health-check window in time. This is an app-level startup problem (e.g. slow migrations, misconfigured connection string causing a hang), not a Lightsail platform issue.
- `"<name> could not be resolved (3: Host not found)"` in the proxy's logs, paired with `502` responses — the pod-networking issue from item 4 (proxy using a container name instead of `localhost`).

## 9. No IaC path fits this tier well

Lightsail Container Service at this scale (a handful of containers, `nano`/`micro` power) doesn't have a natural Terraform/CloudFormation-first workflow the way ECS+RDS does — it's realistically CLI-managed: `push-container-image` + `create-container-service-deployment` by hand or from a script. Treat `containers.json` + `public-endpoint.json` as the actual source of truth for what's deployed, not as a rendering step from IaC.

## 10. Secrets management

There's no first-class secrets-manager integration for container environment variables at this tier — DB passwords, signing keys, etc. go in as plain env var values inside `containers.json`. Treat that file as sensitive:
- Gitignore the real `containers.json`.
- Keep a redacted `containers.json.example` checked in (same shape, placeholder values) so the structure is documented without leaking secrets.

==============================================

Powershell Skill.Md:

---
name: powershell
description: Windows/PowerShell terminal gotchas learned from handing multi-step CLI instructions to a user on a Windows 11 + PowerShell dev box — line continuation, interactive password prompts, and working-directory assumptions. Use when giving the user PowerShell commands to run themselves, or diagnosing a PowerShell/Windows-terminal execution problem they report.
---
# PowerShell
A handful of gotchas from actually handing PowerShell commands to a Windows user mid-task, not a PowerShell tutorial.
## 1. Bash-style line continuation breaks
**Symptom:** a multi-line command using a trailing `\` fails with something like `Missing expression after unary operator '--'.`
**Cause:** PowerShell doesn't treat `\` as a line-continuation character.
**Fix:** use a trailing backtick (`` ` ``) for continuation, or just collapse the command to one line. Never hand a Windows/PowerShell user a bash-style `\`-continued multi-line command.
## 2. Interactive password prompts look hung
**Symptom:** a command that prompts `Enter password:` (e.g. `mysql -h host -u user -p`) appears to accept no input at all — no asterisks, no cursor feedback — from both Command Prompt and a PowerShell admin window. It isn't actually hung, but it reads that way and derails the task.
**Fix:** don't rely on the interactive prompt for anything scripted or handed to a user mid-task — pass the credential inline instead, e.g. `mysql -h host -u user -p'password' ...` (no space after `-p`). If the CLI tool isn't installed on the Windows host at all, prefer borrowing it from an already-running container via `docker exec <container> <cli-command>` rather than asking the user to install a native Windows client.
## 3. Working-directory assumptions silently break multi-step instructions
**Symptom:** a step assumes the user is still at the project root (e.g. `PS C:\project>`), but they're actually sitting inside a `mysql>` prompt or a different shell context left over from an earlier step, and the step fails in a confusing way.
**Fix:** when handing over a multi-step sequence, state the expected prompt/location at each step explicitly rather than assuming continuity from the previous one.

==============================================

Docker Skill.Md:

---
name: docker
description: Docker/Docker Compose gotchas learned running a Windows 11 host with Docker Desktop and Linux containers for a .NET/React app — dependency rebuilds, UTF-8 BOM, borrowing a container's CLI client, and node_modules bind-mount shadowing. Use when working with Dockerfiles or docker-compose.yml, or diagnosing a Docker build/runtime issue, especially on a Windows host running Linux containers.
---
# Docker
A handful of gotchas from real Docker/Compose friction on a Windows-host + Linux-container setup, not a Docker tutorial.
## 1. `--build` on one service still rebuilds its dependencies
**Symptom:** `docker compose up -d --build frontend-ui` fails on an unrelated, currently-broken `backend-api` build, even though only the frontend was meant to be touched.
**Cause:** Compose builds/starts anything the target service `depends_on`, not just the named service.
**Fix:** build the target in isolation first — `docker compose build <service>` (build only, doesn't touch dependencies) — then restart just that container without its siblings: `docker compose up -d --no-deps <service>`.
## 2. UTF-8 BOM causes cross-platform friction
**Symptom:** a Windows-ecosystem `.editorconfig` mandating `charset = utf-8-bom` produces files that break tooling once it runs inside Linux containers — in this project it failed `dotnet format --verify-no-changes` on auto-generated EF migration files.
**Fix:** when a Windows-authored repo's editor defaults assume BOM but the containers are Linux-based, expect this friction and strip the BOM from the generated files rather than fighting the formatter or trying to make every container Windows-based.
## 3. Borrow a CLI client from a running container instead of installing one
**Symptom:** need to run a one-off CLI command (e.g. `mysql`) against some database, but the client isn't installed on the Windows host.
**Fix:** reuse an already-running local container's bundled client against any target, including a remote one: `docker exec <local-container> mysql -h <any-host> -u <user> -p'<password>' <db> -e "<sql>"`. Works equally well against the local dev DB and a remote database (e.g. AWS RDS/Lightsail) — no need to install anything extra on the host.
## 4. Bind-mounting source on Windows can shadow the container's own `node_modules`
**Symptom:** a Node container built fine but breaks once a source bind mount is added — packages built for Linux get overwritten by whatever (or nothing) is on the Windows host.
**Cause:** a bind mount like `./frontend:/app` overwrites the container's own `node_modules` (installed for Linux) with the host's copy.
**Fix:** add an anonymous volume for just that path so the container keeps its own copy: `volumes: [./frontend:/app, /app/node_modules]`.


Comments

Popular posts from this blog

GHL Email Campaigns

Await

Free AI Tools