Files
egress-proxies-operator/CLAUDE.md
Jan Novak e614264597 Require exact command snippets in plan execution summaries
The Step 0 entry described what happened in prose but omitted the actual
kubebuilder/go install invocations, which is exactly the detail a future
reader would want to copy and reproduce. Codifies "include the real
command line, not a paraphrase" in CLAUDE.md and rewrites the Step 0
entry with the exact commands run, including the go install path
correction (kubebuilder v4.15.0 is the module root now, not
.../cmd/kubebuilder) and the controller-gen invocations kubebuilder ran
on its own.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 20:37:08 +02:00

187 lines
8.2 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
A Kubernetes operator for managing egress proxies — currently an empty scaffold with
no controller code yet. Intended shape: a controller-runtime manager reconciling
custom resources (or existing workload types) to provision/configure egress proxy
infrastructure. TODO: confirm the actual CRD(s)/API group once implemented.
## Commands
No Makefile, linter, or entrypoint exists yet. Verified state as of bootstrap:
```bash
go build ./... # nothing to build yet — no .go source files exist
go test ./... # no test files exist yet
```
No linting or formatting tools are configured in this project yet — `golangci-lint`
and `gofumpt` are pre-approved in `.claude/settings.json` for when they're wired up,
but neither has a config file or CI step yet. There is no `main.go` or `cmd/`
entrypoint yet, so there's nothing to run locally.
## Architecture
Not yet built. TODO: once the controller-runtime manager and reconcile loop exist,
document the data-flow diagram and package/role table here, following the standard
reconcile-loop shape: fetch → resolve → list related → compute desired state → merge
→ patch only on diff.
## Conventions
### Go Conventions
- Use the latest stable Go version (check https://go.dev/dl/ before starting a new feature).
- Use `slog` for structured logging.
- `context.Context` is the first parameter of every function that does I/O or can be cancelled.
- No `init()` unless there is no other option.
- Error wrapping: `fmt.Errorf("...: %w", err)` for single errors; `errors.Join` for multiple.
- Prefer stdlib over third-party dependencies where reasonable.
- No vendoring unless explicitly requested.
- Fail fast, return early.
- No obvious comments.
### Testing
**All new Go code must have corresponding tests.**
- Use stdlib `testing` — no testify unless already present in the module.
- Table-driven tests are the default pattern.
- Test files live next to source: `foo.go``foo_test.go`.
- Name tests `Test<Function>_<scenario>` (e.g. `TestParseRoster_emptyInput`).
- Use `t.Parallel()` where safe.
- Use subtests for table entries: `t.Run(tc.name, func(t *testing.T) { ... })`.
- Test behaviour, not implementation.
- Guard slow tests with `testing.Short()`: `if testing.Short() { t.Skip() }`.
- Integration tests that need real infra (DB, network) go behind `//go:build integration`
and use `testcontainers-go` rather than mocking the infra away.
#### Useful test commands
```bash
go test ./... # all unit tests
go test -v ./... # verbose
go test -cover ./... # with coverage
go test -short ./... # skip slow/integration tests
go test -v ./internal/... # specific package tree
go test -race -v -run TestName ./path/to/package # single test, race detector on
go test -tags=integration ./... # integration tests (requires infra)
```
### Plans
When Claude Code's plan mode is used, save the plan file inside the repo at
`docs/plans/YYYY-MM-DD-HHMM-<slug>.md` instead of the default `~/.claude/plans/`
location. Get the timestamp with `date "+%Y-%m-%d-%H%M"`. The `<slug>` is a short
kebab-case summary of the plan's topic.
Include the same timestamp in the plan's header, e.g.:
# Plan: <title>
**Created:** 2026-08-07 15:30
Create `docs/plans/` on first use. Plan files are committed to the repo so other
contributors can review historical decisions.
**Ordering matters:** plan mode itself restricts writes to the default
`~/.claude/plans/` location — that's a hard tool restriction during plan mode, not a
choice. So the copy into `docs/plans/` cannot happen until *after* `ExitPlanMode`.
When it happens, it must be the very first action taken post-exit, committed on its
own, *before* any implementation work starts (branching, scaffolding, editing code).
Do not fold the plan-file commit into the first implementation commit, and do not
defer it until "later" in the same turn — treat "save and commit the plan" as its own
checkpoint that blocks starting Step 0.
### Plan execution summaries
After finishing each step of an approved plan, append a short, human-readable summary
to `docs/plans-executions/YYYY-MM-DD-HHMM-<slug>.md` — same timestamp and slug as the
originating plan in `docs/plans/`, so the two files pair up 1:1. Create the file (and
`docs/plans-executions/` on first use) after the first step completes; append a new
section per step after that, in chronological order (bottom of the file), not
newest-first like `CHANGELOG.md`.
Keep the prose light — a few sentences on what was done, plus anything genuinely
interesting or non-obvious about how it went (a judgment call made, a spec gap found,
something that didn't work as expected). This is not a duplicate of the plan or the
diff; skip steps that went exactly as planned with nothing worth flagging.
**Include exact commands.** Any invocation of an external tool that isn't a plain file
edit — CLI scaffolding tools (`kubebuilder`, code generators), package installs, other
non-obvious shell commands — goes in as a fenced code block with the exact
command-line actually run, not a paraphrase. Prefer the real invocation over a
description of it; a future reader (or a future Claude) should be able to copy the
snippet and reproduce the step. Trim noisy stdout, but keep anything that changed the
outcome (a flag that mattered, an unexpected error, a version that got picked
automatically). Commit the summary update together with that step's implementation
commit.
### Changelog
Maintain a running changelog in `CHANGELOG.md` at the repo root. After every
significant change, fix, or update — once the user confirms it works — append a new
entry **at the top** of the file in this format:
## YYYY-MM-DD HH:MM TZ — short title
- One-line summary of what changed and why.
- Key files touched (optional, only if useful for traceability).
Get the timestamp with `date "+%Y-%m-%d %H:%M %Z"`. Never write a literal placeholder
like `HH:MM` — always run `date` first to get the real current time. Skip trivial edits
(typos, formatting, comment tweaks); only log changes a future reader would care about.
### Branching & Merge Requests
The remote is Gitea (`gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator`). For
**features**, do not commit to `main` directly. Use a branch + merge request flow:
1. **Create a branch off `main`** before starting work:
- `feat/<slug>` for features (e.g. `feat/roster-import`)
- `fix/<slug>` for bug-fix branches the user explicitly asks for
- `<slug>` is short kebab-case
2. **Commit on the branch** following the commit conventions below.
3. **Push the branch** to `origin` with `-u` so it tracks.
4. **Open the MR with `tea`** rather than printing a compare URL:
```bash
tea pr create \
--title "<short title>" \
--description "<body>" \
--base main \
--head <branch>
```
`tea` is already authenticated against the Gitea instance; just run it. Print the
resulting PR URL for the user. If `tea` is unavailable, fall back to printing the
compare URL (`gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/compare/main...<branch>`)
and let the user open the MR manually.
5. **Do not merge or delete the branch** from the CLI — neither via `tea`, `gh`, nor
`git push --delete`. The user does that in Gitea.
**Exceptions — committing straight to `main` is fine for:**
- Small bug fixes / hotfixes the user describes as such.
- Typo / comment / formatting tweaks.
- Edits the user explicitly says to push to `main`.
When uncertain whether something is a feature or a small fix, ask before branching.
### Git Commits
Always append a `Co-Authored-By` trailer to indicate AI assistance:
Co-Authored-By: Claude <noreply@anthropic.com>
TODO: no `.gitea/workflows/` CI pipeline exists yet — add a CI/CD subsection here once
one is set up.
## Gotchas
- This repo currently contains only `go.mod` (module
`gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator`) — no controller code,
`main.go`, Dockerfile, k8s manifests, Makefile, or CI config exist yet. Nothing in
this file describes working software; it's the convention scaffold to build against.