Skip to content

Commit 27df25a

Browse files
hvn2k1claudeHien Vu
authored
chore(claude): add dev container skills for Claude Code (#2741)
* chore(claude): add dev container skills for Claude Code Add three project skills that route development actions through the Bucketeer dev container, where the toolchain is guaranteed: - devc: detect the running dev container (local devcontainer or GitHub Codespace) and run any command inside it via scripts/devc-exec.sh - devc-generate: proto/mock generation inside the container (protoc v23.4 guaranteed; host version mismatch churns every generated file) - devc-deploy: minikube deploys inside the container, incl. the faster single-service rollout path Also update .claude/CLAUDE.md to prefer the dev container + minikube flow for these actions, with Docker Compose as the host-based alternative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: harden devc-exec.sh detection and status reporting Address review comments on PR #2741: - Guard kubectl get pods in the status report; print a clear message when kubectl fails while minikube is up instead of a misleading 0-pod count - Derive the repo root from the script location for an exact devcontainer.local_folder label match from any cwd; drop the fuzzy fallback that could pick the wrong container when multiple checkouts are running Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: remove unrelated datadog-agent manifest from this branch manifests/datadog-agent.yaml was accidentally included in the previous commit; it is local work unrelated to this PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: rename devc skills to devcontainer-* and split docs by audience Address review comments on PR #2741: - Rename skills for clarity: devc -> devcontainer-run, devc-generate -> devcontainer-generate, devc-deploy -> devcontainer-deploy; the wrapper script is now .claude/skills/devcontainer-run/scripts/exec.sh - Move human-facing environment knowledge into DEVELOPMENT.md (working with the dev container from the host, start-minikube exit-1 note, single-service redeploy flow) and cross-reference it from the skills, which keep only the Claude-oriented operational detail Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update SKILL.md * fix(claude): pin dev-container skills to the minikube context Address review comments on PR #2741: - Name the kube context explicitly in every cluster command (kubectl --context minikube, helm --kube-context minikube) and warn in `status` when the active context is not minikube, so a stray `kubectl config use-context` cannot redirect a deploy at a real cluster. - Route the chart-level `helm upgrade` through $DEVC like every other deploy command instead of leaving it to run on the host. - Run the protoc-header spot-check through $DEVC: in codespace mode a bare grep reads the host clone and can falsely validate a stale file. - Refuse to guess between multiple available Bucketeer codespaces; exit 2 with the list and honour an explicit BUCKETEER_CODESPACE override. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Hien Vu <s28320@cyberagent.email>
1 parent d411823 commit 27df25a

6 files changed

Lines changed: 433 additions & 7 deletions

File tree

.claude/CLAUDE.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,26 @@ make mockgen # Regenerate only mocks (after changing interfaces that h
8989
- Run `make proto-all` after any `.proto` file change — this regenerates Go bindings and OpenAPI/Swagger specs.
9090
- Run `make mockgen` after changing any Go interface that has generated mocks in a `mock/` directory.
9191
- The generated files are committed to the repo. `protoc` v23.4 must be on PATH ahead of any other version for the version header in `.pb.go` files to stay at `v4.23.4`.
92+
- Prefer running generation inside the dev container via the `devcontainer-generate` skill — the container guarantees protoc v23.4, while a host version mismatch churns every generated file.
9293

9394
### Local development
9495

95-
**Docker Compose (recommended for most development):**
96+
**Dev container + Minikube (preferred):**
97+
98+
Development actions — proto generation, builds, deploys, kubectl/helm — should run **inside the Bucketeer dev container**, where tool versions are guaranteed (protoc v23.4, go-tools, minikube/helm/kubectl). Check for a running dev container first before running these on the host. Use the project skills:
99+
100+
- `devcontainer-run` — detect the running dev container (local devcontainer or Codespace) and run any command inside it: `bash .claude/skills/devcontainer-run/scripts/exec.sh status`
101+
- `devcontainer-generate` — proto/mock generation inside the container
102+
- `devcontainer-deploy` — deploy to the minikube cluster inside the container
103+
104+
```bash
105+
make start-minikube # Inside the dev container. Always use this, not `minikube start` directly
106+
make deploy-bucketeer # Deploy all Helm charts to minikube
107+
```
108+
109+
Never run kubectl/helm bare on the host — the host kubectl context may point at a real GKE cluster, not minikube.
110+
111+
**Docker Compose (host-based alternative):**
96112
```bash
97113
make docker-compose-up # Start all services
98114
make docker-compose-status # Check status
@@ -107,12 +123,6 @@ Add to `/etc/hosts`:
107123
127.0.0.1 api-gateway.bucketeer.io
108124
```
109125

110-
**Minikube (Kubernetes-based):**
111-
```bash
112-
make start-minikube # Always use this, not `minikube start` directly
113-
make deploy-bucketeer # Deploy all Helm charts
114-
```
115-
116126
### Database migrations
117127
```bash
118128
make migration-validate # Validate migration files with Atlas
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
name: devcontainer-deploy
3+
description: >-
4+
Build and deploy Bucketeer to the minikube cluster inside the dev container,
5+
or redeploy/restart a single service there. Use this whenever the user wants
6+
to deploy locally, run "make deploy-bucketeer", start minikube, get their
7+
code changes running in the dev cluster, restart a crashing pod, or says
8+
"devcontainer-deploy", "deploy to minikube", "redeploy the backend". Also use it to
9+
check deployment health (pods not ready, gateway not responding) in the dev
10+
container environment.
11+
---
12+
13+
# devcontainer-deploy — deploy Bucketeer inside the dev container
14+
15+
Deployment target is the minikube cluster *inside* the dev container (helm
16+
charts in `manifests/`), not the host docker-compose stack. (Human-facing
17+
docs for these flows: `DEVELOPMENT.md` § "Deploy Bucketeer".) All commands go
18+
through the devcontainer-run wrapper (see the `devcontainer-run` skill):
19+
20+
```bash
21+
DEVC="bash .claude/skills/devcontainer-run/scripts/exec.sh"
22+
```
23+
24+
## 1. Preflight
25+
26+
```bash
27+
$DEVC status
28+
```
29+
30+
- `dockerd` not running → start it (command is in the status output) — image
31+
builds need it.
32+
- `minikube` not running → `$DEVC 'make start-minikube'`. Never `minikube start`
33+
directly. If minikube IS already running, skip this: the target intentionally
34+
exits 1 with "minikube is already running" — that is not an error to fix.
35+
36+
## 2. Full deploy
37+
38+
```bash
39+
$DEVC 'make deploy-bucketeer'
40+
```
41+
42+
What it does, so failures are diagnosable: uninstalls the existing `bucketeer`
43+
helm release → regenerates cert/token/oauth secrets → builds all Go binaries →
44+
builds docker images with `TAG=localenv` → loads them into minikube → helm
45+
install/upgrade `localenv` (MySQL, Redis, Pub/Sub emulator, optionally
46+
Postgres/BigQuery emulator) → helm install `bucketeer` with
47+
`manifests/bucketeer/values.dev.yaml`.
48+
49+
This takes many minutes. Run it with a 600000 timeout or `run_in_background`
50+
and monitor. Postgres/BigQuery enablement is auto-detected from
51+
`dataWarehouse` in `values.dev.yaml` — don't set it manually, but remember the
52+
invariant: `web` and `subscriber` must use the same event store, so data
53+
warehouse changes belong in `values.dev.yaml`, not ad-hoc helm flags.
54+
55+
## 3. Single service — faster than a full deploy
56+
57+
For a code change to one service (e.g. backend):
58+
59+
```bash
60+
$DEVC 'make build-go-embed && TAG=localenv make build-docker-images && TAG=localenv make minikube-load-images'
61+
$DEVC 'kubectl --context minikube rollout restart deployment <name> && kubectl --context minikube rollout status deployment <name>'
62+
```
63+
64+
The Bucketeer deployments are `api`, `web`, `batch-server`, and `subscriber`
65+
(confirm with `$DEVC 'kubectl --context minikube get deployments'`). Chart-level
66+
changes instead:
67+
68+
```bash
69+
$DEVC 'helm upgrade bucketeer manifests/bucketeer/ --kube-context minikube --values manifests/bucketeer/values.dev.yaml'
70+
```
71+
72+
Always go through `$DEVC` and always name the context: a bare `helm`/`kubectl`
73+
runs against whatever context is currently active, which on the host is often a
74+
real cluster. `$DEVC status` warns when the active context is not `minikube`.
75+
76+
## 4. Verify
77+
78+
```bash
79+
$DEVC 'kubectl --context minikube get pods' # everything Running/Completed, restarts not climbing
80+
$DEVC 'curl -sk https://api-gateway.bucketeer.io/health' # must run INSIDE the container
81+
```
82+
83+
The `*.bucketeer.io` hosts entries live in the container's `/etc/hosts`
84+
(pointed at `minikube ip`) — curl from the host proves nothing. For a failing
85+
pod: `$DEVC 'kubectl --context minikube logs deploy/<name> --tail=100'` and
86+
`$DEVC 'kubectl --context minikube describe pod <pod>'`.
87+
88+
## Related dev-cluster chores
89+
90+
- Bootstrap e2e accounts (after a fresh deploy, before e2e tests):
91+
`$DEVC 'make create-dev-container-e2e-accounts'`
92+
- Wipe e2e data: `$DEVC 'make delete-dev-container-mysql-data'` (or the
93+
`-postgres-` variant). These are destructive — confirm with the user first.
94+
- MySQL from inside the container: host `$(minikube ip)`, port 32000,
95+
user/pass `bucketeer`, db `bucketeer`.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
name: devcontainer-generate
3+
description: >-
4+
Regenerate Bucketeer protobuf Go bindings, OpenAPI/Swagger specs, and gomock
5+
files inside the dev container, where protoc is guaranteed to be exactly
6+
v23.4. Use this whenever a .proto file changed, generated *.pb.go /
7+
*.pb.gw.go / swagger files need regenerating, a mocked Go interface changed
8+
(mockgen), or the user says "generate proto", "regen protos", "make
9+
proto-all", "make mockgen", or "devcontainer-generate". Prefer this over running
10+
protoc or make proto-all on the host — a host protoc version mismatch
11+
silently rewrites every generated file's header.
12+
---
13+
14+
# devcontainer-generate — code generation inside the dev container
15+
16+
Generated files are committed to the repo, and their headers record the protoc
17+
version (`protoc v4.23.4`). The dev container ships exactly protoc 23.4, so
18+
generation must happen there; a different host protoc churns every `.pb.go`
19+
file and the PR becomes unreviewable. (Human-facing background:
20+
`DEVELOPMENT.md` § "Working with the dev container from the host".)
21+
22+
All commands below go through the devcontainer-run wrapper (see the `devcontainer-run` skill for how
23+
detection works):
24+
25+
```bash
26+
DEVC="bash .claude/skills/devcontainer-run/scripts/exec.sh"
27+
```
28+
29+
## 1. Pick the right target
30+
31+
| What changed | Target |
32+
|---|---|
33+
| `.proto` files | `make proto-all` |
34+
| A Go interface that has generated mocks in a `mock/` dir | `make mockgen` |
35+
| Both, or unsure | `make generate-all` |
36+
37+
## 2. Run it
38+
39+
```bash
40+
$DEVC 'make proto-all' # or make mockgen / make generate-all
41+
```
42+
43+
This is minutes-long; use a generous Bash timeout (600000). If the run fails
44+
on protolock, the `.proto` change broke backward compatibility — read the
45+
error; don't force it without flagging the compatibility break to the user.
46+
47+
## 3. Verify before declaring success
48+
49+
- `git status --porcelain` (on the host for a local devcontainer; inside via
50+
`$DEVC 'git status --porcelain'` for a codespace) — the changed files should
51+
be only the ones related to your proto/interface change plus their generated
52+
outputs. **A diff touching every `.pb.go` in the repo means a wrong protoc
53+
version — abort and check `$DEVC 'protoc --version'`.**
54+
- Spot-check one regenerated file's header still says `protoc v4.23.4`:
55+
`$DEVC 'grep -m1 "protoc " proto/<domain>/<file>.pb.go'` — run it through
56+
`$DEVC`, not bare: in codespace mode the host clone is a *different* checkout,
57+
so a bare `grep` would validate a stale file that was never regenerated.
58+
- Build still compiles: `$DEVC 'make build-go'` (or the affected
59+
`make build-<service>`), and `$DEVC 'make gofmt'` after any Go changes.
60+
61+
## Codespace caveat
62+
63+
In a codespace the regenerated files land in the codespace's clone, not the
64+
host repo. Commit/push from inside, or copy back with `gh codespace cp`. The
65+
`status` subcommand of the devcontainer-run script tells you which mode you're in.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
name: devcontainer-run
3+
description: >-
4+
Detect the running Bucketeer dev container (local VS Code devcontainer or
5+
GitHub Codespace) and run commands inside it. Use this whenever a task should
6+
run in the dev container environment — make targets, builds, tests, kubectl /
7+
helm / minikube commands, checking whether the container is up — or when the
8+
user says "devcontainer-run", "devc", "dev container", "devcontainer", "codespace", or "run this
9+
inside the container". Also use it when a task needs tools the container
10+
guarantees but the host may lack (protoc 23.4, mockgen, protolock, helm,
11+
kubectl, minikube). devcontainer-generate and devcontainer-deploy build on this skill.
12+
---
13+
14+
# devcontainer-run — run commands inside the Bucketeer dev container
15+
16+
The dev container is the canonical Bucketeer development environment: Ubuntu with
17+
docker-in-docker, minikube + helm + kubectl, protoc v23.4, and Go tooling in
18+
`/home/codespace/go-tools/bin` (a persistent volume, NOT on PATH in plain
19+
non-login shells). The workspace is `/workspaces/bucketeer`, the user is
20+
`codespace` (passwordless sudo).
21+
22+
Human-facing documentation for this environment lives in `DEVELOPMENT.md`
23+
("Working with the dev container from the host" and the Minikube sections);
24+
this skill is the Claude-oriented operational version — when changing one,
25+
keep the other in sync.
26+
27+
## How to run anything inside it
28+
29+
Always go through the wrapper script — it finds the container and sets up PATH:
30+
31+
```bash
32+
# Where is the container, and is the environment healthy?
33+
bash .claude/skills/devcontainer-run/scripts/exec.sh status
34+
35+
# Run any command in /workspaces/bucketeer inside the container
36+
bash .claude/skills/devcontainer-run/scripts/exec.sh 'make build-api'
37+
bash .claude/skills/devcontainer-run/scripts/exec.sh 'kubectl get pods'
38+
```
39+
40+
Detection order (the script handles all of this):
41+
1. Already inside the container (`/workspaces/bucketeer` exists, user `codespace`) → run directly.
42+
2. Local devcontainer → `docker ps` filtered by label `devcontainer.local_folder=<repo root>`, exec via `docker exec`.
43+
3. GitHub Codespace → `gh codespace list` (needs the `codespace` auth scope), exec via `gh codespace ssh`.
44+
45+
If more than one available Bucketeer codespace matches (a fork is also named
46+
`bucketeer`, or you keep several), the script refuses to guess and exits 2 with
47+
the list — pick one with `export BUCKETEER_CODESPACE=<name>`.
48+
49+
Exit code 2 means no container was found (or the codespace was ambiguous); the
50+
script prints how to start one.
51+
Don't fall back to running the command on the host in that case — tell the user
52+
and let them choose, because host tool versions (especially protoc) may differ.
53+
54+
## Local devcontainer vs Codespace — the one difference that matters
55+
56+
- **Local devcontainer**: `/workspaces/bucketeer` is a bind mount of the host
57+
repo. Files generated inside appear in the host working tree immediately.
58+
- **Codespace**: a separate clone. Generated or edited files stay in the
59+
codespace. To get them back: commit and push from inside, or
60+
`gh codespace cp 'remote:/workspaces/bucketeer/<path>' <local-path>`.
61+
Always tell the user which mode you're in when file changes are involved
62+
(`status` prints it).
63+
64+
## Environment facts and gotchas
65+
66+
- Long commands (image builds, deploys) can take many minutes — use a generous
67+
Bash timeout (600000) or `run_in_background`.
68+
- `dockerd` inside the container is started by the post-attach hook, but that
69+
only fires when an editor attaches. If `status` says it's not running:
70+
`bash .claude/skills/devcontainer-run/scripts/exec.sh 'nohup sudo dockerd > /tmp/dockerd.log 2>&1 & sleep 5 && docker info > /dev/null && echo ok'`
71+
- minikube must be started with `make start-minikube`, never `minikube start`
72+
directly (the make target restores the cluster config and localenv services).
73+
Note: `make start-minikube` intentionally **exits 1 if minikube is already
74+
running** — check `minikube status` first instead of treating that as failure.
75+
- `web-gateway.bucketeer.io` / `api-gateway.bucketeer.io` resolve via the
76+
container's own `/etc/hosts` (pointed at `minikube ip`). Health checks with
77+
curl against those hosts must run *inside* the container, not on the host.
78+
- If go-tools are missing or permissions look broken, the fix is the setup
79+
script: `bash .devcontainer/setup.sh` (idempotent, cache-aware).
80+
- **Never run kubectl/helm bare on the host for dev work.** The host's kubectl
81+
context may point at a real GKE cluster, not minikube — always go through the
82+
wrapper so commands hit the cluster inside the container.
83+
- The host may also run a docker-compose Bucketeer stack in parallel
84+
(`docker-compose/compose.yml`). That is a different environment — this skill
85+
is only about the dev container / minikube world.

0 commit comments

Comments
 (0)