The plan for this build was written to docs/plans/ only after Step 0's implementation had already started, instead of as its own first action right after ExitPlanMode. CLAUDE.md said *where* to save plans but not *when* relative to other work, so that ordering wasn't actually enforced. Makes it explicit: copying the plan into docs/plans/ and committing it is its own checkpoint that blocks starting Step 0. Also adds a docs/plans-executions/ convention: one running, chronological summary file per plan, appended to after each completed step, for a human-readable narrative of how the plan actually went (judgment calls, spec gaps, surprises) without duplicating the plan or the diff. Backfills the Step 0 entry for the proxy-operator plan retroactively. Co-Authored-By: Claude <noreply@anthropic.com>
178 lines
7.6 KiB
Markdown
178 lines
7.6 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 each entry 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. 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.
|