Implement **Stage 1 only** of the approved plan at `/Users/rockliang/.claude/plans/fluttering-cooking-thunder.md`. Read that file first — it is the spec. Do not implement Stage 2, 3 or 4. ## Already done, do not redo Stage 0 passed. The Forgejo registry returns distinct, correctly-ordered image creation timestamps, so `newest-build` is viable: ``` rock/api-gateway v0.0.0 2026-08-20T05:19:48.655Z rock/api-gateway v0.1.0 2026-08-20T06:57:11.943Z rock/api-gateway v0.1.1 2026-08-20T07:10:13.093Z ``` Note the images are multi-arch OCI indexes: reading `created` means descending index -> amd64 manifest -> config blob. ## Scope: Stage 1 = A1, A2, A4, A6, B, C1 - **A1** — in `~/workplace/homelab`, replace the per-repo Forgejo entry in `k8s/argocd/projects/homelab-project.yaml` `sourceRepos` with a wildcard `https://forgejo.riotpiao.com/rock/*`. - **A2** — add an Argo `Application` at sync-wave `-1` that syncs `k8s/argocd/projects/`. Nothing owns that directory today, which is why the AppProject only ever reaches the cluster by hand. - **A4** — Forgejo webhook to `https://argocd.riotpiao.com/api/webhook` with a shared secret stored in `argocd-secret` (SOPS/ksops). Register it on `rock/homelab` and `rock/homelab-frontend`. - **A6** — add the `forgejo-registry` dockerconfigjson pull secret for any namespace that needs it, as a new `*.enc.yaml` listed in `k8s/argocd/secrets/secret-generator.yaml`. It currently exists only in `api`. - **B + C1** — in `~/workplace/homelab-frontend`: delete the dead `.github/workflows/ci.yml`, add `.forgejo/workflows/ci.yaml` and `.forgejo/workflows/build.yaml`, and add a multi-stage distroless `Dockerfile` (none exists today). Stage 1 stops before Argo CD Image Updater. Do **not** install it and do not add image-updater annotations — that is Stage 2. ## Hard constraints - **`runs-on: docker`.** That is the runner's only registered label. The existing `.github/workflows/ci.yml` uses `ubuntu-latest`, which is exactly why it has never executed once. - **No git tags, ever.** Image tag is the commit short SHA: `$(git rev-parse --short HEAD)`. Do not use `git describe`, do not create or push tags, do not use `latest`. - **Build workflow only builds and pushes.** No manifest write-back, no git push from CI, no `[skip ci]` guard needed. - **GitOps only.** No `kubectl apply`, no `helm upgrade`, no local `terraform apply`. `kubectl --dry-run=server` and read-only `kubectl get`/`logs` are fine. - **Never `git reset --hard`.** - Push directly to `main`, no PRs, no branches. The cluster repo has three remotes — `origin` is Forgejo, `github` is GitHub. Push to both; they are currently in sync at `43483da`. - Match surrounding file style. This repo comments the *why* on non-obvious config, and `kustomization.yaml` uses explicit `resources:` allowlists — a file you add and forget to list is silently dropped. ## Verify before claiming done - `kubectl kustomize` each directory you touch. - `kubectl apply --dry-run=server -f` every manifest you add or change. - Confirm the AppProject wildcard is live: `kubectl -n argocd get appproject homelab -o jsonpath='{.spec.sourceRepos}'` - Push an empty commit to `homelab-frontend` and confirm the build job actually runs on the Forgejo runner and pushes `forgejo.riotpiao.com/rock/api-gateway:`. A workflow that does not trigger is the single most likely failure here. - Report what you verified with real command output, not assertions. If a step fails, say so and stop rather than working around it. Kubeconfig: `/Users/rockliang/workplace/homelab/cluster-config/kubeconfig`.