From b46d2df8499bf8e6fdee3973ba43b3bb3e3b6de5 Mon Sep 17 00:00:00 2001 From: "Walden, Laurance" Date: Sat, 28 Mar 2026 17:27:28 -0700 Subject: [PATCH] chore: update AIAgentMinder to v3.3.0 Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/aiagentminder-version | 2 +- .claude/commands/aam-self-review.md | 23 ++++++- .claude/rules/README.md | 6 +- .claude/rules/approach-first.md | 1 + .claude/rules/architecture-fitness.md | 78 +++++++++++++-------- .claude/rules/sprint-workflow.md | 25 ++++--- .claude/scripts/context-cycle-hook.sh | 87 ++++++++++++++++++++++++ .claude/scripts/context-cycle.sh | 2 +- .claude/scripts/sprint-update.sh | 97 +++++++++++++++++++++++++++ .claude/settings.json | 8 +++ .gitignore | 2 +- 11 files changed, 287 insertions(+), 44 deletions(-) create mode 100644 .claude/scripts/context-cycle-hook.sh create mode 100644 .claude/scripts/sprint-update.sh diff --git a/.claude/aiagentminder-version b/.claude/aiagentminder-version index a4f52a5..15a2799 100644 --- a/.claude/aiagentminder-version +++ b/.claude/aiagentminder-version @@ -1 +1 @@ -3.2.0 \ No newline at end of file +3.3.0 diff --git a/.claude/commands/aam-self-review.md b/.claude/commands/aam-self-review.md index de96d5e..54adb2b 100644 --- a/.claude/commands/aam-self-review.md +++ b/.claude/commands/aam-self-review.md @@ -29,7 +29,8 @@ When invoked manually, ask the user which lens to apply (or accept all three for **A) Security** — injection, auth bypass, data exposure, hardcoded secrets **B) Performance** — N+1 queries, unbounded loops, missing indexes, blocking I/O **C) API Design** — consistency with existing endpoints, naming conventions, error response shapes -**D) All three** (default) +**D) Cost Impact** — paid API call patterns, retry/fallback designs that could cause runaway costs, unbounded batch sizes sent to paid services +**E) All four** (default) --- @@ -93,6 +94,25 @@ DIFF: [paste diff here] ``` +### Cost Impact Lens prompt: +``` +You are a cost-aware code reviewer. Review the following diff for designs that could cause unexpected costs with paid external services. + +Focus on: +- Retry loops or fallback chains that re-send work to a paid API (each retry costs money) +- Fallback paths that re-process already-handled items instead of only unhandled ones +- Unbounded batch sizes sent to paid services (no cap on items per request) +- Missing circuit breakers or rate limits on paid API calls +- Error handling that swallows failures silently, causing upstream retries +- SDK or package upgrades that change API versions without updating all integration points (webhook endpoints, serialization contracts) + +For each issue found: state the file, line range, issue type, severity (High/Medium/Low), and a one-line fix recommendation. +If no issues found: state "Cost impact review: no issues found." + +DIFF: +[paste diff here] +``` + --- ## Step 4: Consolidate and Act @@ -106,6 +126,7 @@ After all subagents complete: Security: [X issues / no issues] Performance: [X issues / no issues] API Design: [X issues / no issues] + Cost Impact: [X issues / no issues] [List all findings by severity: High → Medium → Low] ``` diff --git a/.claude/rules/README.md b/.claude/rules/README.md index fc865c6..bcc0803 100644 --- a/.claude/rules/README.md +++ b/.claude/rules/README.md @@ -1,6 +1,8 @@ # .claude/rules/ -Rules files loaded natively by Claude Code at every session start. No hooks required. +Rules files loaded natively by Claude Code at every session start. + +Context cycling is enforced by a `PreToolUse` hook (`context-cycle-hook.sh`) configured in `settings.json`, not by rules alone. All `.md` files in this directory are auto-discovered and loaded automatically. Delete a file to disable that rule. @@ -14,6 +16,6 @@ All `.md` files in this directory are auto-discovered and loaded automatically. | `correction-capture.md` | Correction capture — flags repeated wrong-first-approach patterns and proposes permanent instructions (always active) | | `code-quality.md` | TDD cycle, build-before-commit, review-before-commit, error handling (optional) | | `sprint-workflow.md` | Sprint governance over native Tasks — planning, approval gates, context cycling, review/archive (optional) | -| `architecture-fitness.md` | Structural constraints — layer boundaries, external API rules, etc. (optional, customize for your project) | +| `architecture-fitness.md` | Structural constraints — file size, secrets, test isolation, layer boundaries (optional, ships with defaults) | Add your own `.md` files here for project-specific rules. Files support YAML frontmatter with `globs:` patterns to scope rules to specific file paths. diff --git a/.claude/rules/approach-first.md b/.claude/rules/approach-first.md index 5243bbc..4bec468 100644 --- a/.claude/rules/approach-first.md +++ b/.claude/rules/approach-first.md @@ -18,6 +18,7 @@ Before executing, write a brief approach statement: 1. **What** you're going to do (one sentence) 2. **Which files** will be created or modified (list them) 3. **Key assumptions** — anything the user should know before you start +4. **Cost/billing impact** — if the change touches a paid external service (API calls, webhooks, cloud resources), state the expected cost implications of the design. Flag designs where a failure mode could cause runaway costs (e.g., retry loops hitting a paid API, fallback paths that re-process already-handled work). Keep it short. This is a check-in, not a design doc. diff --git a/.claude/rules/architecture-fitness.md b/.claude/rules/architecture-fitness.md index dc6e194..f4c24cc 100644 --- a/.claude/rules/architecture-fitness.md +++ b/.claude/rules/architecture-fitness.md @@ -9,8 +9,8 @@ description: Architecture fitness rules — structural constraints for this proj ## How to Use This File These rules are enforced by Claude during code review, PR creation, and when writing new code. -Replace the examples below with constraints that match YOUR project's architecture. -Each rule should be specific enough that Claude can check it mechanically. +The defaults below are stack-agnostic starting points. Tighten, relax, or replace them +to match YOUR project's architecture. Remove sections that don't apply. Rules that apply only to certain file types can be scoped with glob patterns in the frontmatter: ```yaml @@ -21,43 +21,67 @@ globs: ["src/routes/**", "src/handlers/**"] ## Structural Constraints - +### File Size -### Layer Boundaries - - - +If a source file exceeds 300 lines, flag it for decomposition before adding more code. +A file that large usually contains more than one responsibility. Split by extracting +a helper, a subcomponent, or a dedicated module — don't just continue appending. -[Define your layer boundary rules here] +Generated files (migrations, lock files, snapshots) are exempt. -### External API Calls +### Secrets in Source - - +No hardcoded credentials, API keys, tokens, passwords, or connection strings in source files. +Use environment variables, `.env` files (gitignored), secret managers (Azure Key Vault, AWS SSM, +1Password CLI, Bitwarden CLI), or framework-provided config binding. -[Define where external calls are allowed here] +Patterns to catch: string literals assigned to variables named `key`, `secret`, `token`, +`password`, `apiKey`, `connectionString`, `auth`; Base64-encoded blobs in config files; +URLs containing credentials (`https://user:pass@`). ### Test Isolation - - +Test files live in a dedicated directory (e.g., `tests/`, `__tests__/`, `*.test.*` co-located +by framework convention) — not scattered arbitrarily through source directories. + +Each test file must be independently runnable. Test files must not import from other test files. +Shared fixtures and helpers belong in a dedicated test utilities location (e.g., `tests/helpers/`, +`tests/__fixtures__/`, `tests/conftest.py`), not inside individual test files. + +### Layer Boundaries + +External HTTP calls and direct database access belong in dedicated service or client modules — +not in route handlers, UI components, CLI entrypoints, or middleware. + +This ensures retry logic, auth headers, error handling, and connection management are +centralized rather than duplicated across call sites. + +Does not apply to projects with only one source file or no external dependencies. + + + + + -[Define your test structure rules here] + -### File Size Limits + - - + -[Define your size thresholds here] + --- diff --git a/.claude/rules/sprint-workflow.md b/.claude/rules/sprint-workflow.md index fbdeced..0674ca2 100644 --- a/.claude/rules/sprint-workflow.md +++ b/.claude/rules/sprint-workflow.md @@ -11,8 +11,8 @@ Sprint governance (bounded scope, approval gates, review/archive) tracks in `SPR ``` PLAN → SPEC → APPROVE → [per item: EXECUTE → TEST → REVIEW → MERGE → VALIDATE] → COMPLETE - ↑ - CONTEXT_CYCLE (at NEXT transition) + ↑ + CONTEXT_CYCLE (hook-enforced, any tool call) ``` **Human checkpoints** (pause for input): PLAN (approve issues), APPROVE (approve specs), BLOCKED, REWORK. @@ -70,6 +70,7 @@ Write detailed spec per item before coding. **Post-Merge Validation:** {deploy-dependent tests, or "None"} **Files:** Create: {list} | Modify: {list} **Dependencies:** {other items, or "None"} +**Upgrade Impact:** {if upgrading an SDK/package that changes API versions: list all integration points to verify — webhook endpoints, API clients, serialization contracts, config files. Or "N/A"} **Custom Instructions:** {human-provided, or "None"} ``` @@ -77,7 +78,7 @@ Present all specs together. User may: approve all, revise items, add custom inst ## APPROVE -1. Update `SPRINT.md` status to `in-progress`. +1. Run `bash .claude/scripts/sprint-update.sh sprint-status in-progress` to update sprint status. 2. Create native Task per issue (title with risk tag, description: AC + spec summary + issue ID, dependencies from spec). 3. Confirm: "Sprint S{n} started. {count} tasks. Beginning execution." @@ -85,7 +86,7 @@ Present all specs together. User may: approve all, revise items, add custom inst ## EXECUTE -1. Update Task to `in_progress`, SPRINT.md row to `in-progress`. +1. Update Task to `in_progress`. Run `bash .claude/scripts/sprint-update.sh status S{n}-{seq} in-progress`. 2. Read spec + relevant source files. 3. Branch: `{type}/S{n}-{seq}-{short-desc}`. 4. TDD RED → TDD GREEN → Refactor → Integration/E2E if spec defines → Full test suite (zero failures; investigate unrelated failures as regressions). @@ -107,14 +108,14 @@ Present all specs together. User may: approve all, revise items, add custom inst ## MERGE -1. `git checkout main && git pull`. 2. Update Task to `completed`, SPRINT.md row to `done`. 3. Check spec for post-merge validation. +1. `git checkout main && git pull`. 2. Update Task to `completed`. Run `bash .claude/scripts/sprint-update.sh status S{n}-{seq} done`. 3. Check spec for post-merge validation. → Post-merge exists → VALIDATE. None → NEXT. ## VALIDATE 1. If deployed env needed, poll availability (max 15 min; if exceeded, notify human, continue to NEXT — Post-Merge stays `pending`, **sprint cannot close until validated**). -2. Run post-merge tests. Update SPRINT.md Post-Merge: `pass`, `fail`, or `pending`. A `pending` validation is a blocking obligation, not informational. +2. Run post-merge tests. Run `bash .claude/scripts/sprint-update.sh postmerge S{n}-{seq} pass` (or `fail` / `pending: {desc}`). A `pending` validation is a blocking obligation, not informational. → Pass → NEXT. Fail → REWORK. Deferred → NEXT (pending remains). @@ -128,9 +129,11 @@ Present all specs together. User may: approve all, revise items, add custom inst ## NEXT -1. Find next `todo` in SPRINT.md. 2. Complete any deferred VALIDATE steps now ready. 3. Context pressure check (see CONTEXT_CYCLE). +1. Find next `todo` in SPRINT.md. 2. Complete any deferred VALIDATE steps now ready. -→ Cycle needed → CONTEXT_CYCLE. Next exists → EXECUTE. All `done` + all Post-Merge `pass`/`n/a` → COMPLETE. All `done` but any `pending` → execute those validations — **do not present sprint review**. +→ Next exists → EXECUTE. All `done` + all Post-Merge `pass`/`n/a` → COMPLETE. All `done` but any `pending` → execute those validations — **do not present sprint review**. + +Note: Context cycling is enforced by the `PreToolUse` hook — it fires on every tool call, not just at NEXT transitions. If cycling is needed, non-cycle tools will be blocked automatically. ## COMPLETE @@ -152,13 +155,13 @@ Present all specs together. User may: approve all, revise items, add custom inst Any state → BLOCKED when: external dependency unavailable, missing credentials, ambiguous AC, debug checkpoint (3 failed attempts), test needs human action, pipeline escalation. -Update SPRINT.md to `blocked`. Notify human: what, why, what unblocks. Wait. → Human resolves → return to prior state. +Run `bash .claude/scripts/sprint-update.sh status S{n}-{seq} blocked`. Notify human: what, why, what unblocks. Wait. → Human resolves → return to prior state. ## CONTEXT_CYCLE -Autonomous context management at NEXT transitions. Persists state, self-terminates, fresh session resumes (requires profile hook or sprint-runner). +Autonomous context management. Persists state, self-terminates, fresh session resumes (requires profile hook or sprint-runner). -**Primary signal:** Read `.context-usage` in the project root. If the file exists and `should_cycle` is `true`, cycle. Thresholds: 250k tokens Sonnet, 350k Opus, 35% unknown models. +**Enforcement:** A `PreToolUse` hook (`context-cycle-hook.sh`) reads `.context-usage` on every tool call. When `should_cycle` is `true`, the hook **blocks all tool calls except Bash, Write, and Read** — which are the only tools needed to execute the cycle steps below. This is involuntary; the agent cannot skip or delay it. Thresholds: 250k tokens Sonnet, 350k Opus, 35% unknown models. **Fallback** (`.context-usage` absent — status line not configured): Cycle when ANY true: 3+ items completed this session | debug checkpoint triggered | rework executed. When in doubt, cycle. diff --git a/.claude/scripts/context-cycle-hook.sh b/.claude/scripts/context-cycle-hook.sh new file mode 100644 index 0000000..c407277 --- /dev/null +++ b/.claude/scripts/context-cycle-hook.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# context-cycle-hook.sh — PreToolUse hook that enforces context cycling. +# +# When .context-usage says should_cycle=true, this hook BLOCKS tool calls +# (exit 2) except for Bash and Write, which are needed to execute the +# CONTEXT_CYCLE procedure (commit work, write continuation file, self-terminate). +# +# This replaces the voluntary "check at NEXT transitions" rule with involuntary +# enforcement — the agent cannot ignore it because blocked tools fail. +# +# Configured in .claude/settings.json: +# "hooks": { +# "PreToolUse": [{ +# "type": "command", +# "command": "bash .claude/scripts/context-cycle-hook.sh" +# }] +# } +# +# Input: JSON on stdin with tool_name, tool_input fields (from Claude Code hooks protocol). +# Output: stdout message shown to Claude. Exit 0 = allow, exit 2 = block. + +set -euo pipefail + +# Read hook input from stdin +input=$(cat) + +# Locate .context-usage relative to the project root. +# The hook runs from the project root (cwd), so look there first. +USAGE_FILE=".context-usage" + +# If .context-usage doesn't exist, nothing to enforce — allow everything. +if [ ! -f "$USAGE_FILE" ]; then + exit 0 +fi + +# Parse should_cycle from the file. Requires jq. +if ! command -v jq >/dev/null 2>&1; then + # Can't check without jq — fail open (allow). + exit 0 +fi + +should_cycle=$(jq -r '.should_cycle // false' "$USAGE_FILE" 2>/dev/null) + +# If cycling not needed, allow everything. +if [ "$should_cycle" != "true" ]; then + exit 0 +fi + +# --- Cycling IS needed. Determine whether to block this tool call. --- + +# Extract the tool name from hook input. +tool_name=$(echo "$input" | jq -r '.tool_name // "unknown"' 2>/dev/null) + +# Allow tools needed for the CONTEXT_CYCLE procedure itself: +# Bash — git commit, running context-cycle.sh +# Write — .sprint-continuation.md, .sprint-continue-signal +# Read — reading SPRINT.md/specs to write the continuation file +case "$tool_name" in + Bash|Write|Read) + # Allow through, but still warn. + used_tokens=$(jq -r '.used_tokens // "unknown"' "$USAGE_FILE" 2>/dev/null) + threshold=$(jq -r '.threshold // "unknown"' "$USAGE_FILE" 2>/dev/null) + echo "CONTEXT CYCLE OVERDUE — $used_tokens tokens used (threshold: $threshold). Execute CONTEXT_CYCLE protocol now. These tool calls are only allowed for cycle steps (commit, write continuation, terminate)." + exit 0 + ;; +esac + +# Block all other tools with a clear directive. +used_tokens=$(jq -r '.used_tokens // "unknown"' "$USAGE_FILE" 2>/dev/null) +threshold=$(jq -r '.threshold // "unknown"' "$USAGE_FILE" 2>/dev/null) +used_pct=$(jq -r '.used_pct // "unknown"' "$USAGE_FILE" 2>/dev/null) + +cat < +# bash .claude/scripts/sprint-update.sh postmerge +# bash .claude/scripts/sprint-update.sh sprint-status +# +# Examples: +# bash .claude/scripts/sprint-update.sh status S1-001 in-progress +# bash .claude/scripts/sprint-update.sh postmerge S1-002 pass +# bash .claude/scripts/sprint-update.sh sprint-status in-progress + +SPRINT_FILE="SPRINT.md" + +die() { echo "Error: $1" >&2; exit 1; } + +if [ $# -lt 1 ]; then + die "Usage: sprint-update.sh [issue-id] " +fi + +subcmd="$1" +shift + +[ -f "$SPRINT_FILE" ] || die "SPRINT.md not found in current directory" + +case "$subcmd" in + status) + [ $# -eq 2 ] || die "Usage: sprint-update.sh status " + issue_id="$1" + new_value="$2" + + # Column 5 (Status) in the pipe-delimited table + # Find the row starting with | | and replace column 5 + if ! grep -q "^| *${issue_id} *|" "$SPRINT_FILE"; then + die "Issue '${issue_id}' not found in SPRINT.md" + fi + + awk -v id="$issue_id" -v val="$new_value" ' + BEGIN { FS="|"; OFS="|" } + { + # Match table rows where field 2 (trimmed) equals the issue ID + trimmed = $2 + gsub(/^ +| +$/, "", trimmed) + if (trimmed == id) { + # Replace field 6 (Status column, 1-indexed with leading empty field) + $6 = " " val " " + } + print + } + ' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE" + ;; + + postmerge) + [ $# -ge 2 ] || die "Usage: sprint-update.sh postmerge " + issue_id="$1" + shift + # Join remaining args to support "pending: some description" + new_value="$*" + + if ! grep -q "^| *${issue_id} *|" "$SPRINT_FILE"; then + die "Issue '${issue_id}' not found in SPRINT.md" + fi + + awk -v id="$issue_id" -v val="$new_value" ' + BEGIN { FS="|"; OFS="|" } + { + trimmed = $2 + gsub(/^ +| +$/, "", trimmed) + if (trimmed == id) { + # Replace field 7 (Post-Merge column) — last data field before trailing | + $7 = " " val " " + } + print + } + ' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE" + ;; + + sprint-status) + [ $# -eq 1 ] || die "Usage: sprint-update.sh sprint-status " + new_value="$1" + + if ! grep -q '^\*\*Status:\*\*' "$SPRINT_FILE"; then + die "Sprint status line not found in SPRINT.md" + fi + + awk -v val="$new_value" ' + /^\*\*Status:\*\*/ { print "**Status:** " val; next } + { print } + ' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE" + ;; + + *) + die "Unknown subcommand '${subcmd}'. Usage: sprint-update.sh [issue-id] " + ;; +esac diff --git a/.claude/settings.json b/.claude/settings.json index a9d4e42..ea73bcb 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -75,5 +75,13 @@ "Bash(git push --force:*)", "Bash(git push -f:*)" ] + }, + "hooks": { + "PreToolUse": [ + { + "type": "command", + "command": "bash .claude/scripts/context-cycle-hook.sh" + } + ] } } diff --git a/.gitignore b/.gitignore index 45e10ad..2317ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ config.local.* # IDE and Editor .idea/ -.vscode/ + *.swp *.swo *~