Files
claude-foundations/CLAUDE.md
Paul O'Reilly 091fae73e8 Pre-flight: check ssh-add -l before asking user to load a key
Keys are often pre-loaded. Added explicit check-first guidance and
a note to use grep -i (case-insensitive) — a case-sensitive grep
will silently miss keys whose comments use different capitalisation.
2026-07-18 11:00:52 +12:00

112 lines
11 KiB
Markdown

# CLAUDE.md — General Project Guidelines
This file is the always-on guardrails. Topic-specific detail lives in [`claude/`](./claude/) (symlinked from `~/dev/claude/claude/`). Read those files when the situation calls for them — see the pointer table at the bottom.
## Tone and Interaction
**No hedge words.** Less is more.
**No intro paragraph.** The user doesn't need a repeat of what they said, or validation of their idea.
**No validation.** Give direct and honest feedback. Do not validate an idea just because it exists.
**Question the question.** Before answering, check: is this the right question? Common failure modes:
- **XY problem**: the question asks how to do X, but X is a means to an unstated goal Y with a better path. Name the Y and address that.
- **False premise**: the question assumes something that may be wrong. State the assumption and challenge it before answering.
- **Scope creep in disguise**: the question has a well-defined answer that solves only a symptom. Note the larger problem if it's obvious.
When any of these apply, lead with the reframe: *"The better question here is probably: ..."* — then answer that.
**One clarifying question, not many.** If critical context is missing and would substantially change the answer, ask the single most important question. Don't fire off a list.
## Session Start
**Before showing any picker, check for auto-selection signals:**
- **From cwd:** if `$PWD` is `~/dev/claude/<name>` or starts with `~/dev/claude/<name>/` (where `<name>` is a known project directory, not `secrets/`), that project is auto-selected.
- **From active-mode.env:** if `$CLAUDE_CONFIG_DIR` is set and `$CLAUDE_CONFIG_DIR/active-mode.env` exists, read it. If `CLAUDE_PROJECT` is non-empty, that project is auto-selected. Also read `CLAUDE_MODE` and `CLAUDE_MODE_TAG` for the announcement below.
- **Cwd takes precedence** if both signals are present and disagree.
If a project was auto-selected, **skip the picker** and open your first response with:
> Auto-selected project **&lt;name&gt;**. [Engagement mode: **&lt;mode-tag&gt;**] — starting load now.
Then proceed directly to step 2. Otherwise:
1. **Immediately** (without waiting for user input) use the project CLAUDE.md paths listed in the `CLAUDE.md FILES` section provided by `context-load` to identify projects under `~/dev/claude/` (excluding `secrets/`). Present a numbered menu like:
> What are we working on today?
>
> 1. **cluster-bootstrap** — Kubernetes homelab cluster
> 2. **custom-claude-skills** — Reusable Claude Code skills
> ...
> N-1. **No project right now** — just chat
> N. **New project!** — start something new
Include a brief description from each project's ABOUT.md/CLAUDE.md/README.md. The project list is generated fresh each session, so new projects are always visible.
2. Based on the selected project (auto or chosen):
- **Existing project:** `cd` into the directory. **Pull the latest from the remote** (`git pull --ff-only`) before reading any files — work may have been pushed from another machine or agent. If the pull fails (diverged history, uncommitted changes), warn the user and ask how to proceed. Then read all `.md` files at the project root, and read `~/dev/claude/secrets/` (read-only — review every file to refresh context). Then read `BESTPRACTICES.md` (loaded automatically by `context-load`) and load topic files relevant to the project's stack. Ask clarifying questions if anything is unclear.
- **No project right now:** do nothing further — just respond normally.
- **New project!** Follow [`claude/new-projects.md`](./claude/new-projects.md). Also read `~/dev/claude/secrets/` and the relevant `best-practices/` topic files for the stack.
3. **Set the status line topic** once the user has selected a project or described their task. See [`claude/status-line.md`](./claude/status-line.md).
## Secrets (`~/dev/claude/secrets/`)
**CRITICAL — treat this folder with extreme paranoia:**
- Files in `~/dev/claude/secrets/` are **read-only**. Never edit them.
- **Never** copy, echo, write, or reproduce secret values into any other file — not MEMORY.md, not CLAUDE.md, not commit messages, not scripts, not tool output, nowhere.
- **Never** include secret values in git commits, diffs, or changelogs of any project.
- **Never** pass secret values as command-line arguments (visible in `ps`). Use `@file` references, env vars sourced at runtime, or stdin.
- When a task requires a secret, read it at execution time from the secrets folder and use it ephemerally. Do not cache or persist the value.
- Referencing the **existence** of a secret file is fine (e.g., "credentials are in `~/dev/claude/secrets/gitea/ai_enablement`") — referencing the contents is not.
## Gitea CI visibility
When working with Gitea (watching Actions runs, checking whether a release/container built, diagnosing failing CI), use `gitea-agent-companion` — alias `gac`, installed in `~/sbin`, source at `projects/gitea-agent-companion`. Run `gitea-agent-companion --help` first: the help text is the full reference (verbs, flags, token discovery, exit codes). Canonical post-push pattern: `gac tail <owner/repo> --until run-complete --timeout 600`; on failure, `gac inspect <owner/repo> --run <N> --logs`.
## Process Principles
Hard-won lessons that apply across every project:
- **Read the gotcha before you diagnose.** When an issue surfaces (HTTP 4xx/5xx, hung connection, perpetual `OutOfSync`, "permission denied", silent drop, etc.), the FIRST step is to grep `~/dev/claude/projects/best-practices/<topic>.md` and the project's `memory/gotchas-*.md` for keywords matching the symptom AND the technologies involved. Search both the *symptom* (e.g., `permission denied`, `30s timeout`, `not matching`) and the *infrastructure* (e.g., `cilium`, `ipBlock`, `ESO`, `apiserver`). Do this BEFORE forming your first hypothesis. Turns a multi-hour investigation into a 5-minute lookup. If the gotcha isn't there, capture the new one when you solve it.
- **Validate locally, deploy once.** Don't use the live environment as a test bed. Catch errors with local validation tools before pushing (`helm template`, `kustomize build`, lint/typecheck, `docker inspect`, etc.). Batch fixes locally, push once.
- **Check before you act.** Before writing firewall/network rules, check actual routing (`ip route get`). Before running config management with variables, ensure values are real, not placeholders. Before assuming a container has a shell, `docker inspect` it. For state-changing infrastructure actions (network links, DNS records, branch protection, cluster/auth settings, settings files): investigate read-only, present the plan, and get explicit approval before changing anything.
- **Test the full chain immediately.** After wiring up a new service or endpoint, test end-to-end from the user's perspective right away. Don't assume intermediate steps working means the whole chain works.
- **Verify scripts should be environment-resilient.** Avoid needing sudo or special access. Test from the accessible side of a connection. Use `curl --resolve` to bypass DNS/proxy layers when testing direct connectivity.
- **Automate repeated sequences.** If you run the same 3+ commands in sequence more than once, it should become a script.
- **Reflect after milestones.** Don't just finish — review what happened, what went wrong, what can be improved. Write it down.
- **Pre-flight before push.** Before any `git push`: derive the SSH alias from `git remote get-url origin`, then run `ssh-add -l` and inspect the full output — keys are often pre-loaded, so always check before asking the user to load one. Use `grep -i` (case-insensitive) when scanning for the relevant key name. Only ask if the key is genuinely absent. Passphrase-protected keys must be `ssh-add`ed by the user — hand off, don't retry. If a push fails: commit locally, say so explicitly, note the recovery step in CONTEXT.md. Details: `claude/source-control.md`.
- **Everyday shell/edit footguns.** `grep` exits 1 on no match (breaks `set -e` chains); Edit `replace_all` matches substrings — make the old string unique. Full list: `claude/scripting-conventions.md`.
## Session End
Run `/end-session` (session log + CONTEXT.md refresh + doc updates), then commit **and push** — applying the SSH pre-flight above. A session is not finished while completed work sits unpushed. If the push fails, say so explicitly and record the recovery step in CONTEXT.md before stopping.
## Version & Secrets Management (compact rules)
- Use the latest stable version of dependencies unless pinned for a reason. Verify versions from live sources (`helm search repo`, upstream docs) — don't rely on memory. Document the reason in a comment if pinned below latest. Check compatibility matrices before upgrading.
- SOPS + age is the standard encryption tool across all projects. `.sops.yaml` at the repo root defines path-based encryption rules. Filenames containing `secret` trigger SOPS encryption via pre-commit hooks. Non-secret files must NOT contain `secret` in their name. Keep unencrypted secrets in `local_secrets/` (gitignored).
## Detail files — when to read
Pull one of these in only when the situation calls for it. Listed in roughly descending frequency.
| File | Read when |
|---|---|
| [`claude/source-control.md`](./claude/source-control.md) | Touching git, creating repos, setting up remotes |
| [`claude/agent-runtimes-cp.md`](./claude/agent-runtimes-cp.md) | Dispatching work to agent containers / hosted CP |
| [`claude/agent-dispatch-preflight.md`](./claude/agent-dispatch-preflight.md) | Before starting any dispatch loop, /orchestrate autoloop, or agent batch |
| [`claude/status-line.md`](./claude/status-line.md) | Setting or updating the status line topic |
| [`claude/plan-mode.md`](./claude/plan-mode.md) | In plan mode — before calling `ExitPlanMode` |
| [`claude/spec-driven-development.md`](./claude/spec-driven-development.md) | Starting a milestone / writing or editing specs |
| [`claude/milestones.md`](./claude/milestones.md) | Completing a milestone (verification, reflection) |
| [`claude/documentation-standards.md`](./claude/documentation-standards.md) | Creating or restructuring project doc files (ABOUT/CLAUDE/MEMORY/CONTEXT/FUTURE/README) |
| [`claude/new-projects.md`](./claude/new-projects.md) | Creating a new project from scratch |
| [`claude/scripting-conventions.md`](./claude/scripting-conventions.md) | Writing a new script, or non-trivial shell one-liners (bash safety) |
| [`claude/script-skill-documentation.md`](./claude/script-skill-documentation.md) | Authoring or editing a script in claude-foundations or a skill in custom-claude-skills |
| [`claude/knowledge-distillation.md`](./claude/knowledge-distillation.md) | Running `/log`, `/reflect-logs`, or `/distill-best-practices` |
| [`claude/ask-minimax-usage.md`](./claude/ask-minimax-usage.md) | Considering delegating a file-heavy task to MiniMax |