# 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/` or starts with `~/dev/claude//` (where `` 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 **<name>**. [Engagement mode: **<mode-tag>**] — 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 --until run-complete --timeout 600`; on failure, `gac inspect --run --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/.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 | | [`claude/impeccable.md`](./claude/impeccable.md) | Skill maintenance/install for Impeccable (design skill): updating the version, re-applying the no-auto-invoke flag, hint-shim sync, detector usage |