Add context-load/start-claude scripts and clean up CLAUDE.md

context-load walks from cwd upward, loading CLAUDE.md, CONTEXT.md,
MEMORY.md, and BESTPRACTICES.md files with directory trees and git
status. start-claude wraps the claude CLI with --append-system-prompt.

CLAUDE.md: removed Ansible/Helm sections (in best-practices/), folded
Validate Before Deploying into Process Principles, deduped secrets
bullet, fixed best-practices path references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-03-13 11:49:40 +13:00
parent 00fa1af898
commit a463dc0793
3 changed files with 179 additions and 31 deletions

View File

@@ -15,9 +15,9 @@
Scan the directories at runtime so the list is always current. Include a brief description if the project has a CLAUDE.md or README.md you can glean one from.
2. Based on the user's choice:
- **Existing project**: `cd` into the directory, read all `.md` files, and read `~/dev/claude/secrets/` (read-only reference — review every file to refresh context). Then read the [Best Practices Index](best-practices/INDEX.md) and load any topic files relevant to the selected project's technology stack. Ask clarifying questions if anything is unclear or incomplete, and note context in MEMORY.md.
- **Existing project**: `cd` into the directory, read all `.md` files, and read `~/dev/claude/secrets/` (read-only reference — review every file to refresh context). Then read the [Best Practices Index](best-practices/INDEX.md) in the `claude-foundations` repo and load any topic files relevant to the selected project's technology stack. Ask clarifying questions if anything is unclear or incomplete, and note context in MEMORY.md.
- **No project right now**: Do nothing further — just respond normally.
- **New project!**: Follow the "New Projects" section below. Also read `~/dev/claude/secrets/` as above. Read the [Best Practices Index](best-practices/INDEX.md) and load topic files relevant to the new project's technology stack.
- **New project!**: Follow the "New Projects" section below. Also read `~/dev/claude/secrets/` as above. Read the [Best Practices Index](best-practices/INDEX.md) in the `claude-foundations` repo and load topic files relevant to the new project's technology stack.
## Secrets (`~/dev/claude/secrets/`)
@@ -116,7 +116,7 @@ Three skills form a continuous learning pipeline across projects:
1. **`/log`** — Run at end of session. Captures decisions, gotchas, open questions to `memory/log/YYYY-MM-DD.<HHMMSS>.md` in the current project. Also prunes old reflected logs.
2. **`/reflect-logs`** — Run periodically. Processes unprocessed session logs into topic memory files (`memory/gotchas-*.md`, `memory/process-lessons.md`, etc.). Flags stale entries. Tracks state in `.reflection-state.json`.
3. **`/distill-best-practices`** — Run from any project. Reads changed memory files across all tracked projects and proposes updates to `claude-foundations/best-practices/`. Tracks state in `best-practices/.distill-state.json`.
3. **`/distill-best-practices`** — Run from any project. Reads changed memory files across all tracked projects and proposes updates to the `claude-foundations` repo's `best-practices/` folder. Tracks state in `best-practices/.distill-state.json`.
### State Files
- **`.reflection-state.json`** — Per-project, tracks which logs have been reflected on (md5 hashes of log file content)
@@ -145,18 +145,6 @@ Break projects into numbered milestones (M1, M2, ...). Every milestone completio
3. **Updated README.md** — scripts section, milestone table, any new setup steps
4. **Updated CLAUDE.md** — repo structure, conventions, new patterns discovered
## Validate Before Deploying
Every new config, manifest, or template should be validated locally before deploying. The target environment is not a test environment — each deploy-crash-fix cycle wastes time and clutters Git history. Batch fixes locally, push once.
Examples:
- `helm template` for Helm values
- `kustomize build` for Kustomize apps
- `docker run <app> validate-configuration` for app configs
- `docker inspect` for unfamiliar container images
- Lint/typecheck/test for application code
- `curl --resolve` for the full request chain after deployment
## Version Management
- Use the latest stable version of dependencies unless pinned for a reason
@@ -170,7 +158,6 @@ Examples:
- The `.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
- Never pass secrets via command-line arguments (visible in `ps` output) — use `@file` references or environment variables
- Keep unencrypted secrets in `local_secrets/` (gitignored)
## Scripting Conventions
@@ -185,24 +172,10 @@ Examples:
These are hard-won lessons from real project work:
- **Validate locally, deploy once.** Don't use the live environment as a test bed. Catch errors with local validation tools before pushing.
- **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.
- **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 so future sessions benefit.
## Ansible Conventions (where applicable)
- Roles follow standard structure: `tasks/main.yml`, `templates/*.j2`, `handlers/main.yml`
- Jinja2 templates have `.j2` extension and include a "managed by Ansible" header comment
- Variables that need customisation go in `inventory.yml`, not scattered across role defaults
- Always pass `-i inventory.yml` explicitly or run from the directory containing `ansible.cfg`
- Never use placeholder values with `-e` for vars that template config files
## Helm Chart Conventions (where applicable)
- Always validate values against the chart schema before committing
- Run `helm show values <repo>/<chart> --version <ver>` to check actual structure
- Schemas change between versions — field names and nesting can differ from docs or online examples
- A quick `helm template` test locally catches schema errors before deployment

150
scripts/context-load Executable file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env bash
# context-load — Gather project context for a Claude Code session
#
# Walks from cwd upward collecting key index files.
# Outputs structured context to stdout, suitable for --append-system-prompt.
#
# What it loads:
# - Every CLAUDE.md found walking up from cwd (top-down order)
# - Directory tree (depth 3) from each CLAUDE.md location
# - Every CONTEXT.md found walking up from cwd (top-down order)
# - Every MEMORY.md found walking up from cwd (top-down order)
# - Every BESTPRACTICES.md found walking up from cwd (top-down order)
# - All *.md files in cwd
# - git-status-report from the highest-level CLAUDE.md dir
set -uo pipefail
TREE_DEPTH=3
# --- Helpers ---
emit_header() {
echo ""
echo "================================================================"
echo "=== $1"
echo "================================================================"
echo ""
}
emit_file() {
local filepath="$1"
emit_header "FILE: $filepath"
cat "$filepath"
echo ""
}
emit_tree() {
local dir="$1"
emit_header "TREE: $dir (depth $TREE_DEPTH)"
tree -L "$TREE_DEPTH" --charset utf-8 -I '.git|node_modules|__pycache__|.venv|venv' "$dir" 2>/dev/null \
|| find "$dir" -maxdepth "$TREE_DEPTH" -not -path '*/.git/*' -not -path '*/.git' | sort
echo ""
}
strip_ansi() {
sed 's/\x1b\[[0-9;]*m//g'
}
# --- Discovery: walk from cwd upward ---
discover_upward() {
local dir="$PWD"
local dirs=()
while [[ "$dir" != "/" ]]; do
dirs+=("$dir")
dir="$(dirname "$dir")"
done
# Return in top-down order (reverse — highest ancestor first)
for ((i=${#dirs[@]}-1; i>=0; i--)); do
echo "${dirs[$i]}"
done
}
# Collect dirs that have key index files
claude_dirs=()
context_dirs=()
memory_dirs=()
bestpractices_dirs=()
all_hierarchy_dirs=()
while IFS= read -r dir; do
all_hierarchy_dirs+=("$dir")
[[ -f "$dir/CLAUDE.md" ]] && claude_dirs+=("$dir")
[[ -f "$dir/CONTEXT.md" ]] && context_dirs+=("$dir")
[[ -f "$dir/MEMORY.md" ]] && memory_dirs+=("$dir")
[[ -f "$dir/BESTPRACTICES.md" ]] && bestpractices_dirs+=("$dir")
done < <(discover_upward)
if [[ ${#claude_dirs[@]} -eq 0 ]]; then
echo "# No CLAUDE.md found in directory hierarchy" >&2
echo "# Searched from: $PWD" >&2
fi
# --- Output: CLAUDE.md files (top-down) + tree from each ---
# Track files we've already emitted to avoid duplicates
declare -A emitted_files
for dir in "${claude_dirs[@]}"; do
# Resolve symlinks for dedup — two paths might point to the same file
real_path="$(readlink -f "$dir/CLAUDE.md")"
if [[ -z "${emitted_files[$real_path]:-}" ]]; then
emit_file "$dir/CLAUDE.md"
emitted_files["$real_path"]=1
fi
emit_tree "$dir"
done
# --- Output: CONTEXT.md files (top-down) ---
for dir in "${context_dirs[@]}"; do
real_path="$(readlink -f "$dir/CONTEXT.md")"
if [[ -z "${emitted_files[$real_path]:-}" ]]; then
emit_file "$dir/CONTEXT.md"
emitted_files["$real_path"]=1
fi
done
# --- Output: MEMORY.md files (top-down) ---
for dir in "${memory_dirs[@]}"; do
real_path="$(readlink -f "$dir/MEMORY.md")"
if [[ -z "${emitted_files[$real_path]:-}" ]]; then
emit_file "$dir/MEMORY.md"
emitted_files["$real_path"]=1
fi
done
# --- Output: BESTPRACTICES.md files (top-down) ---
for dir in "${bestpractices_dirs[@]}"; do
real_path="$(readlink -f "$dir/BESTPRACTICES.md")"
if [[ -z "${emitted_files[$real_path]:-}" ]]; then
emit_file "$dir/BESTPRACTICES.md"
emitted_files["$real_path"]=1
fi
done
# --- Output: all *.md files in cwd ---
if compgen -G "$PWD"/*.md > /dev/null 2>&1; then
for md_file in "$PWD"/*.md; do
[[ -f "$md_file" ]] || continue
real_path="$(readlink -f "$md_file")"
if [[ -z "${emitted_files[$real_path]:-}" ]]; then
emit_file "$md_file"
emitted_files["$real_path"]=1
fi
done
fi
# --- Output: git status report ---
if [[ ${#claude_dirs[@]} -gt 0 ]]; then
highest_dir="${claude_dirs[0]}"
git_status_report="$(command -v git-status-report 2>/dev/null || true)"
if [[ -n "$git_status_report" ]]; then
emit_header "GIT STATUS: $highest_dir"
"$git_status_report" "$highest_dir" 2>/dev/null | strip_ansi || true
fi
fi

25
scripts/start-claude Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# start-claude — Launch Claude Code with pre-loaded project context
#
# Runs context-load to gather CLAUDE.md files, directory trees,
# CONTEXT.md files, cwd markdown, and git status, then passes
# the result as an appended system prompt.
#
# All arguments are forwarded to claude.
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CONTEXT_LOADER="${SCRIPT_DIR}/context-load"
if [[ ! -x "$CONTEXT_LOADER" ]]; then
echo "Error: context-load not found at $CONTEXT_LOADER" >&2
exit 1
fi
context="$("$CONTEXT_LOADER")"
if [[ -n "$context" ]]; then
exec claude --append-system-prompt "$context" "$@"
else
exec claude "$@"
fi