Add statusline scripts, context-load improvements, and prior distill updates
- Add statusline.sh and set-topic.sh for per-session status line topics - Update context-load with improved directory walking and output format - Update CLAUDE.md with status line docs and early-call safety note - Update MEMORY.md and README.md with new script/skill entries - Add memory files: script-statusline, skill-decompose, skill-orchestrate, gotchas-gitea - Add networking.md best practice (nftables, systemd sockets, Docker forwarding, TLS) - Update best practices from prior distill: documentation, kubernetes, scripting, secrets-management, skills-development - Prune reflected session logs, add new session logs - Update reflection state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,3 +48,7 @@ Human-readable project documentation:
|
||||
- Quick start / setup instructions
|
||||
- Milestone table with status
|
||||
- Scripts section listing every script with purpose and usage
|
||||
|
||||
## Extract Reusable Patterns Early
|
||||
|
||||
When a reusable pattern emerges during project work (a gotcha that applies to any project using the same tool, a process lesson that generalises), extract it into a best-practices guide immediately rather than waiting for a dedicated distillation pass. The guide pays for itself when used to audit and improve the current project in the same session, and benefits all future projects.
|
||||
|
||||
@@ -56,6 +56,11 @@ Manual bootstrap secrets (encryption keys, OIDC client secrets) must be document
|
||||
- **Namespace PodSecurity labels must match container security contexts.** DinD, CSI drivers, and other privileged workloads need `pod-security.kubernetes.io/enforce: privileged` on their namespace. A `baseline` or `restricted` namespace silently blocks privileged pods.
|
||||
- **Document privileged namespace requirements.** When a workload needs elevated privileges, document the specific requirement (e.g., "Docker-in-Docker for CI builds") alongside the namespace label.
|
||||
|
||||
## ArgoCD Source Type Detection
|
||||
|
||||
- **ArgoCD auto-detects Kustomize.** When a source directory contains `kustomization.yaml`, ArgoCD runs Kustomize automatically. Adding an explicit `directory:` source type overrides this detection and causes ArgoCD to try applying `kustomization.yaml` as a raw K8s resource, which fails with schema errors. Remove explicit directory source types from Kustomize sources.
|
||||
- **Credential template URL-prefix must match exactly.** ArgoCD repo-creds secrets use URL prefix matching. When migrating Git server URLs (hostname, protocol, or port changes), update the credential template to match the new prefix. Stale credentials cause "authentication required" errors on all apps using that prefix.
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
- `enableServiceLinks: false` may be needed when K8s-injected service env vars conflict with app config (e.g., Authelia interprets `AUTHELIA_*` service vars as configuration).
|
||||
|
||||
33
best-practices/networking.md
Normal file
33
best-practices/networking.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Networking & Infrastructure
|
||||
|
||||
## nftables Flush Ruleset on Remote Hosts
|
||||
|
||||
On remote hosts, `nftables flush ruleset` followed by a failed rule load leaves the host with NO firewall. SSH survives only on existing connections — new connections are blocked or allowed depending on the default policy.
|
||||
|
||||
**Always validate rules before applying:** `nft -c -f <rulefile>` does a dry-run parse. For extra safety, deploy a cron-based auto-rollback timer that reverts rules unless explicitly confirmed (similar to `shutdown -c` pattern).
|
||||
|
||||
## systemd Socket Activation Overrides Config File Ports
|
||||
|
||||
On modern Linux systems (Ubuntu 24.04+), systemd socket activation controls the listening port for services like SSH. Editing the service config file alone (e.g., `sshd_config Port 2222`) has no effect — the socket unit still binds the original port.
|
||||
|
||||
**Check socket activation first:** `systemctl cat <service>.socket` shows whether socket activation is in play. If so, override the socket unit's `ListenStream` directive, not the service config.
|
||||
|
||||
## Docker Sets iptables FORWARD Policy to DROP
|
||||
|
||||
Docker sets the iptables FORWARD chain default policy to DROP. This affects ALL forwarding on the host, not just Docker traffic. Non-Docker forwarding (VPN, VM bridges, custom NAT) silently breaks.
|
||||
|
||||
**Fix:** Add explicit ACCEPT rules in the `DOCKER-USER` chain for non-Docker forwarding needs. This chain is processed before Docker's own rules and persists across Docker restarts.
|
||||
|
||||
## HTTP Host Header vs TLS SNI Are Different Layers
|
||||
|
||||
When proxying to a backend over HTTPS, two independent identifiers must be set correctly:
|
||||
- **TLS SNI** — sent during the TLS handshake, used for certificate selection. Missing SNI causes `x509: cannot validate certificate for <IP>`.
|
||||
- **HTTP Host header** — sent after TLS is established, used for virtual host routing. Missing or wrong Host header causes 404 from the backend.
|
||||
|
||||
A reverse proxy must set both. They often need to be the same value, but they're configured independently.
|
||||
|
||||
## Wildcard Certs in Auto-Renewing Proxies
|
||||
|
||||
Auto-renewing proxies (Caddy, Traefik with Let's Encrypt, etc.) that also support file-loaded certificates treat file-loaded certs as globally available. A wildcard cert loaded for one site block will match ALL matching subdomains, silently preventing automatic certificate issuance for other sites.
|
||||
|
||||
**Rule:** Use automatic certificate management for all sites. Don't mix file-loaded and automatic certs unless you understand the matching priority.
|
||||
@@ -44,3 +44,5 @@ Every script that modifies state should support `--dryrun` / `-n`:
|
||||
- `grep` interprets option-like strings (starting with `-`) as flags — use `--` terminator before patterns or input that may start with dashes.
|
||||
- Always quote variables in conditionals and file paths
|
||||
- Use `trap` for cleanup of temp files and credentials
|
||||
- **Use `git diff --numstat` for binary file detection** instead of `file`. The `file` command is unreliable (marks shell scripts as "executable"), while `git diff --numstat` shows `-` for binary files using git's robust binary detection heuristics.
|
||||
- **Use `cat -A` to diagnose invisible character issues.** Reveals non-printing characters like em dashes, zero-width spaces, and smart quotes that look identical to correct characters but break YAML parsers, config files, and frontmatter. Essential when a file looks correct but tooling rejects it.
|
||||
|
||||
@@ -42,6 +42,12 @@ Some secrets are chicken-and-egg (e.g., the age decryption key for ArgoCD's KSOP
|
||||
- **Set alerts before expiry.** For long-lived credentials (e.g., 720-day OAuth client secrets), set calendar reminders or automated monitoring alerts well before they expire.
|
||||
- **Rotation plan.** Know the rotation procedure before you need it — some credential types (e.g., Azure app registrations) require coordinated updates across multiple systems.
|
||||
|
||||
## Multi-Field Secret Files
|
||||
|
||||
Secret files that contain multiple fields (e.g., repo URL, token, username) cannot be used as bare values. Consumers must parse individual fields (e.g., `grep + awk` or structured YAML/JSON parsing).
|
||||
|
||||
The multi-field format is preferable because it's self-documenting — all related credentials live together. But any automation reading the file needs extraction logic, not just `cat`.
|
||||
|
||||
## Backup Considerations
|
||||
|
||||
Backup plans must include encryption keys (age private keys, etc.) so that encrypted data in Git repos remains recoverable.
|
||||
|
||||
@@ -34,3 +34,13 @@
|
||||
- **Prefer specific tool patterns over broad ones** — `Bash(git log *)` is safer than `Bash(git *)`
|
||||
- **Fallback to tool instructions for dynamic paths** — if a command needs `$ARGUMENTS` to compute a path, use a plain-text instruction telling Claude to use the Read tool instead
|
||||
- **Env var expansion works** — `${CLAUDE_PROJECT_ROOT}` expands in `!`command`` blocks because they run as shell commands. This is the recommended pattern for portable cross-project paths.
|
||||
|
||||
## Non-ASCII in YAML Frontmatter
|
||||
|
||||
Skills with em dashes (`—`), smart quotes (`"`), or other non-ASCII characters in the YAML frontmatter `description` field fail to load silently — the skill appears as "Unknown skill" with no error message. The markdown body below the frontmatter can contain any characters.
|
||||
|
||||
AI models commonly generate em dashes instead of regular dashes. Always validate skill files (e.g., with `cat -A` or a dedicated validator) before committing.
|
||||
|
||||
## Profile-Independent Skills Directories
|
||||
|
||||
Each Claude Code profile maintains a completely independent skills directory. Skills installed in one profile (e.g., default) are unavailable in other profiles (e.g., `.claude-octopus`). Install scripts must use the profile-aware config directory path rather than hardcoded paths like `~/.claude/skills/`.
|
||||
|
||||
Reference in New Issue
Block a user