@esoteric-logic/praxis-harness 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/base/CLAUDE.md +14 -1
  2. package/base/hooks/auto-format.sh +1 -1
  3. package/base/hooks/dep-audit.sh +1 -1
  4. package/base/hooks/file-guard.sh +3 -3
  5. package/base/hooks/recursion-guard.sh +7 -1
  6. package/base/hooks/session-data-collect.sh +1 -1
  7. package/base/hooks/vault-checkpoint.sh +5 -5
  8. package/base/rules/code-excellence.md +22 -0
  9. package/base/rules/coding.md +16 -0
  10. package/base/rules/observable-code.md +87 -0
  11. package/base/rules/refactor-triggers.md +59 -0
  12. package/base/rules/writing-quality.md +122 -0
  13. package/base/skills/px-complexity-audit/SKILL.md +118 -0
  14. package/base/skills/px-discover/SKILL.md +4 -1
  15. package/base/skills/px-discuss/SKILL.md +4 -1
  16. package/base/skills/px-doc-lint/SKILL.md +107 -0
  17. package/base/skills/px-prose-review/SKILL.md +96 -0
  18. package/base/skills/px-quality-gate/SKILL.md +182 -0
  19. package/base/skills/px-risk/SKILL.md +4 -1
  20. package/base/skills/px-scaffold-new/SKILL.md +16 -14
  21. package/base/skills/px-session-retro/SKILL.md +1 -1
  22. package/base/skills/px-spec/SKILL.md +6 -2
  23. package/base/skills/px-verify/SKILL.md +2 -1
  24. package/bin/praxis.js +27 -6
  25. package/kits/api/install.sh +1 -1
  26. package/kits/api/teardown.sh +1 -1
  27. package/kits/code-quality/hooks/generate-baseline.sh +1 -1
  28. package/kits/code-quality/hooks/post-commit.sh +3 -2
  29. package/kits/code-quality/hooks/pre-push.sh +15 -15
  30. package/kits/code-quality/install.sh +1 -1
  31. package/kits/code-quality/teardown.sh +3 -3
  32. package/kits/data/install.sh +1 -1
  33. package/kits/data/teardown.sh +1 -1
  34. package/kits/infrastructure/install.sh +1 -1
  35. package/kits/infrastructure/teardown.sh +1 -1
  36. package/kits/security/install.sh +1 -1
  37. package/kits/security/teardown.sh +1 -1
  38. package/kits/web-designer/install.sh +1 -1
  39. package/kits/web-designer/teardown.sh +1 -1
  40. package/package.json +1 -1
  41. package/scripts/health-check.sh +21 -15
  42. package/scripts/install-tools.sh +5 -5
  43. package/scripts/lint-harness.sh +1 -1
  44. package/scripts/onboard-mcp.sh +1 -1
  45. package/scripts/test-harness.sh +1 -1
  46. package/scripts/update.sh +1 -1
package/base/CLAUDE.md CHANGED
@@ -125,6 +125,9 @@ Missing servers are non-blocking — features degrade gracefully.
125
125
  - Commit with wrong git identity
126
126
  - Write a file with unreplaced {placeholders}
127
127
  - Use vault search when Obsidian is not running (obsidian backend requires Obsidian open)
128
+ - Mix refactoring and feature changes in one commit — commit refactor separately
129
+ - Copy-paste 3+ lines instead of extracting a shared function
130
+ - Use `console.log`/`fmt.Println`/`print()` for production logging — use the structured logger
128
131
 
129
132
  ## AI-Kit Registry
130
133
  Kits activate via `/px-kit:<n>` slash command. Kits are idempotent — double-activate is a no-op.
@@ -142,7 +145,7 @@ Kit manifests live in `~/.claude/kits/<name>/KIT.md`.
142
145
 
143
146
  ## Rules Registry — Load on Demand Only
144
147
 
145
- ### Universal — always active (12 rules)
148
+ ### Universal — always active (14 rules)
146
149
 
147
150
  Quality is a generation-time constraint, not a post-hoc review. The rules below
148
151
  are the lens you write through — they shape every line of code produced.
@@ -161,6 +164,8 @@ are the lens you write through — they shape every line of code produced.
161
164
  | `~/.claude/rules/context-management.md` | Context anti-rot, phase scoping, context reset protocol |
162
165
  | `~/.claude/rules/memory-boundary.md` | Auto-memory boundary, MEMORY.md cap, dream integration |
163
166
  | `~/.claude/rules/security-posture.md` | Sandbox model, credential protection, protected paths |
167
+ | `~/.claude/rules/writing-quality.md` | Prose constraints — sentence limits, fluff kill list, doc templates, voice rules |
168
+ | `~/.claude/rules/refactor-triggers.md` | Pre-check protocol, commit refactor separately, QUALITY: comment convention |
164
169
 
165
170
  ### Scoped — load only when paths match
166
171
 
@@ -188,11 +193,19 @@ are the lens you write through — they shape every line of code produced.
188
193
  | `~/.claude/rules/live-docs-required.md` | Dependency manifests, files importing external packages |
189
194
  | `~/.claude/rules/desktop-protocol.md` | Claude Desktop ↔ Claude Code handoff sessions |
190
195
 
196
+ #### Application observability
197
+
198
+ | File | Loads when |
199
+ |------|------------|
200
+ | `~/.claude/rules/observable-code.md` | `**/services/**`, `**/handlers/**`, `**/workers/**`, `**/middleware/**`, `**/cmd/**` |
201
+
191
202
  ### Auto-invocable skills (replace former universal rules)
192
203
  | Skill | Triggers when |
193
204
  |-------|--------------|
194
205
  | `px-communication-standards` | Writing client-facing docs, proposals, status reports, commits, PRs |
195
206
  | `px-architecture-patterns` | Writing ADRs, specs, system design, risk docs, blocker reports |
207
+ | `px-quality-gate` | Auto inside /px-verify (Step 1 item 5b) and before /px-ship — blocks on BLOCK findings |
208
+ | `px-doc-lint` | Fast structural markdown check inside px-quality-gate for staged *.md files |
196
209
 
197
210
  ## Judgment & Research Commands
198
211
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # PostToolUse hook — auto-formats files after edit.
3
3
  # Always exits 0 (advisory, never blocks).
4
- set -uo pipefail
4
+ set -euo pipefail
5
5
  trap 'exit 0' ERR
6
6
 
7
7
  INPUT=$(cat)
@@ -2,7 +2,7 @@
2
2
  # dep-audit.sh — PostToolUse:Write|Edit|MultiEdit hook
3
3
  # Runs dependency vulnerability checks when manifest files are modified.
4
4
  # Always exits 0 (advisory only — PostToolUse cannot hard-block).
5
- set -uo pipefail
5
+ set -euo pipefail
6
6
  trap 'exit 0' ERR
7
7
 
8
8
  INPUT=$(cat)
@@ -6,7 +6,7 @@ set -euo pipefail
6
6
  INPUT=$(cat)
7
7
  FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')
8
8
 
9
- if [ -z "$FILE_PATH" ]; then
9
+ if [[ -z "$FILE_PATH" ]]; then
10
10
  exit 0
11
11
  fi
12
12
 
@@ -29,7 +29,7 @@ for pattern in "${PROTECTED_PATTERNS[@]}"; do
29
29
  done
30
30
 
31
31
  # Check project-level protected files from CLAUDE.md if it exists
32
- if [ -f "CLAUDE.md" ]; then
32
+ if [[ -f "CLAUDE.md" ]]; then
33
33
  # Extract paths from ## Protected Files section
34
34
  IN_SECTION=false
35
35
  while IFS= read -r line; do
@@ -42,7 +42,7 @@ if [ -f "CLAUDE.md" ]; then
42
42
  fi
43
43
  if $IN_SECTION && echo "$line" | grep -qE "^- "; then
44
44
  PROTECTED=$(echo "$line" | sed 's/^- //' | sed 's/ *#.*//' | xargs)
45
- if [ -n "$PROTECTED" ] && echo "$FILE_PATH" | grep -qE "$PROTECTED"; then
45
+ if [[ -n "$PROTECTED" ]] && echo "$FILE_PATH" | grep -qE "$PROTECTED"; then
46
46
  echo "BLOCKED: $FILE_PATH matches project-protected pattern '$PROTECTED'. Explain the intended change."
47
47
  exit 2
48
48
  fi
@@ -50,7 +50,13 @@ KEY="${KEY:0:300}"
50
50
 
51
51
  # ── Increment counter ──
52
52
  # Use a hash of the key for safe JSON field names
53
- KEY_HASH=$(echo -n "$KEY" | md5 2>/dev/null || echo -n "$KEY" | md5sum 2>/dev/null | cut -d' ' -f1 || echo "fallback")
53
+ if command -v md5sum &>/dev/null; then
54
+ KEY_HASH=$(echo -n "$KEY" | md5sum | cut -d' ' -f1)
55
+ elif command -v md5 &>/dev/null; then
56
+ KEY_HASH=$(echo -n "$KEY" | md5 -q)
57
+ else
58
+ KEY_HASH="${KEY:0:32}"
59
+ fi
54
60
 
55
61
  COUNT=$(jq -r --arg cat "$CATEGORY" --arg key "$KEY_HASH" \
56
62
  '.[$cat][$key] // 0' "$STATE_FILE" 2>/dev/null || echo "0")
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # Stop hook — collects structured session data and stages it for the Stop prompt.
3
3
  # Always exits 0 (advisory, never blocks session end).
4
- set -uo pipefail
4
+ set -euo pipefail
5
5
  trap 'exit 0' ERR
6
6
 
7
7
  CONFIG_FILE="$HOME/.claude/praxis.config.json"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # PreCompact hook — writes minimal checkpoint to vault before context compaction.
3
3
  # Always exits 0 (advisory, never blocks compaction).
4
- set -uo pipefail
4
+ set -euo pipefail
5
5
  trap 'exit 0' ERR
6
6
 
7
7
  CONFIG_FILE="$HOME/.claude/praxis.config.json"
@@ -19,7 +19,7 @@ PLANS_DIR="$VAULT_PATH/plans"
19
19
  mkdir -p "$PLANS_DIR"
20
20
 
21
21
  DATE=$(date +%Y-%m-%d)
22
- TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
22
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
23
23
  CHECKPOINT_FILE="$PLANS_DIR/$DATE-compact-checkpoint.md"
24
24
 
25
25
  BRANCH=$(git --no-pager rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
@@ -40,16 +40,16 @@ fi
40
40
  LINT_STATE="unknown"
41
41
  TEST_STATE="unknown"
42
42
 
43
- if [ -f "go.mod" ] && command -v golangci-lint &>/dev/null; then
43
+ if [[ -f "go.mod" ]] && command -v golangci-lint &>/dev/null; then
44
44
  LINT_COUNT=$(golangci-lint run ./... 2>&1 | grep -c "^" || true)
45
- if [ "$LINT_COUNT" -eq 0 ]; then
45
+ if [[ "$LINT_COUNT" -eq 0 ]]; then
46
46
  LINT_STATE="clean"
47
47
  else
48
48
  LINT_STATE="$LINT_COUNT findings"
49
49
  fi
50
50
  fi
51
51
 
52
- if [ -f "go.mod" ] && command -v go &>/dev/null; then
52
+ if [[ -f "go.mod" ]] && command -v go &>/dev/null; then
53
53
  if go test ./... -short 2>&1 | grep -q "^ok"; then
54
54
  TEST_STATE="passing"
55
55
  else
@@ -74,3 +74,25 @@ A comment that says `// increment counter` above `counter++` is noise.
74
74
  A comment that says `// retry three times because the upstream API returns 503 on cold start`
75
75
  is knowledge that cannot be inferred from the code alone.
76
76
  Delete the first kind. Write more of the second kind.
77
+
78
+ ---
79
+
80
+ ## Reference Codebases — What Excellence Looks Like
81
+
82
+ When you need a reference for what excellent code looks like, use these:
83
+
84
+ | Domain | Reference | What to study |
85
+ | ------ | --------- | ------------- |
86
+ | C / systems | SQLite source (`sqlite.org/src`) | Discipline: 590x test-to-source ratio, 100% branch coverage, zero external deps |
87
+ | C / network | Redis `src/ae.c`, `src/dict.c` | Naming, readability, data structures that document themselves |
88
+ | Go | Go standard library (`pkg.go.dev/std`) | Idiomatic naming, error design, interface sizing — one method where possible |
89
+ | Rust | `rustc_errors` crate | Error message design: what failed, where, what to do next |
90
+ | Error messages | Elm compiler output | Kindest, most actionable errors in any compiled language |
91
+ | API design | Stripe API (`docs.stripe.com`) | Naming consistency, versioning discipline, error schema |
92
+ | Documentation | Go stdlib `net/http` package docs | Every exported symbol explained by what it does for the caller |
93
+
94
+ When uncertain if code is good enough: "Would this survive a review from the SQLite team?"
95
+ If the answer is no — simplify first.
96
+
97
+ The SQLite standard: every line has a reason. Every function has one job.
98
+ Every error has a message a human can act on.
@@ -13,6 +13,22 @@
13
13
  - If Context7 is unavailable: state that docs could not be verified and flag the
14
14
  specific method/API as "unverified against current version."
15
15
 
16
+ ### Import-trigger protocol
17
+
18
+ Any commit diff that adds a new `import`, `require`, `using`, or `use` statement for an
19
+ external package must have a corresponding Context7 lookup in the same session.
20
+
21
+ Language-specific patterns matched:
22
+
23
+ - JavaScript/TypeScript: `import ... from`, `require(...)`
24
+ - Python: `import ...`, `from ... import`
25
+ - Go: `import "..."` or `import (...)`
26
+ - Rust: `use ...::...`
27
+ - Java/C#: `import ...`, `using ...`
28
+
29
+ Every new external import requires a Context7 verification before the gate clears.
30
+ Internal packages (same repo, same module) are excluded.
31
+
16
32
  ### Tool preferences
17
33
  - Use Read/Edit/Write tools instead of cat/sed/echo.
18
34
  - Use `rg` (ripgrep) for searching code, not grep.
@@ -0,0 +1,87 @@
1
+ # Observable Code — Instrumentation Constraints
2
+ # Scope: **/services/**, **/handlers/**, **/workers/**, **/middleware/**, **/cmd/**
3
+ # Active during code generation for service-layer code
4
+ # Cross-reference: api-quality.md covers request-level logging and correlation IDs.
5
+ # This rule covers application-level observability: structured logging, metrics, traces.
6
+
7
+ Code is not production-ready if it cannot be debugged without attaching a debugger.
8
+ Observable code tells you what happened, when, and why — from logs, metrics, and traces alone.
9
+
10
+ ## Invariants — BLOCK on violation
11
+
12
+ ### Structured logging only
13
+ - All log statements use structured format (key-value pairs, not string interpolation)
14
+ - No `fmt.Println` / `console.log` / `print()` in production code paths — use the structured logger
15
+ - Log at the point of failure, not at the catch site (log once, propagate)
16
+
17
+ ### Log levels are semantic
18
+ - ERROR: something failed and a human needs to know immediately
19
+ - WARN: something unexpected happened but the system recovered
20
+ - INFO: a significant state transition (service started, job completed, user authenticated)
21
+ - DEBUG: internal detail useful during development — must not appear in production by default
22
+
23
+ ### Structured log format — mandatory fields
24
+ ```json
25
+ {
26
+ "timestamp": "ISO-8601 UTC",
27
+ "level": "error|warn|info|debug",
28
+ "service": "service-name",
29
+ "correlation_id": "request or trace identifier",
30
+ "message": "what happened — actionable, not generic",
31
+ "context": { "relevant_key": "relevant_value" }
32
+ }
33
+ ```
34
+
35
+ ### What NOT to log
36
+ - Passwords, tokens, secrets, full credit card numbers
37
+ - Full request/response bodies in production (may contain PII)
38
+ - DEBUG logs in production services (log level must be configurable)
39
+ - The same event more than once in the same request path
40
+
41
+ ### External call discipline
42
+ - Every external call (HTTP, DB, queue) has a timeout
43
+ - Every external call logs duration on completion
44
+ - Failed external calls log: target, duration, error type, and whether retry will occur
45
+
46
+ ## Conventions — WARN on violation
47
+
48
+ ### Metrics naming
49
+ Format: `{service}_{subsystem}_{name}_{unit}`
50
+ All lowercase, underscores as separators.
51
+
52
+ Mandatory metrics per service:
53
+ - `{service}_requests_total` — counter, labeled by method and status code
54
+ - `{service}_errors_total` — counter, labeled by error type
55
+ - `{service}_latency_seconds` — histogram, labeled by operation
56
+ - `{service}_active_connections` or `{service}_queue_depth` — gauge (if applicable)
57
+
58
+ GOOD: `auth_login_attempts_total`, `cache_hit_ratio`, `queue_messages_pending`
59
+ BAD: `loginAttempts`, `CacheHitRatio`, `queue-messages-pending`
60
+
61
+ ### Trace spans (OpenTelemetry)
62
+ Span naming: `{service}/{operation}` — lowercase, slash separator
63
+ GOOD: `auth/validate-token`, `db/query-users`, `cache/get`
64
+ BAD: `validateToken`, `DB Query`, `GET /users`
65
+
66
+ Mandatory span attributes:
67
+ - `service.name`
68
+ - `http.method` and `http.status_code` for HTTP operations
69
+ - `db.system` and `db.operation` for database calls
70
+ - `error.type` and `error.message` on error spans
71
+
72
+ ### Health endpoints
73
+ - Liveness: `/healthz` — "is the process alive?"
74
+ - Readiness: `/readyz` — "can the process serve traffic?"
75
+ - Both return structured JSON with component status
76
+
77
+ ### The Observability Contract
78
+ An error is only production-observable if ALL three are true:
79
+ 1. It appears in structured logs with correlation_id and context
80
+ 2. It increments an error metric labeled by error type
81
+ 3. It is captured in a trace span with error attributes
82
+
83
+ If only one or two are true: the code is not fully observable. Fix before shipping.
84
+
85
+ ## Removal Condition
86
+ Remove when an observability linter or OpenTelemetry SDK auto-instrumentation
87
+ replaces these generation-time constraints entirely.
@@ -0,0 +1,59 @@
1
+ # Refactor Triggers — Pre-Check Protocol
2
+ # Scope: All code modifications
3
+ # Always active during code generation
4
+ # Cross-reference: code-quality.md defines the hard limits (30 lines, 3 nesting,
5
+ # 4 params, 300-line files, no TODO/FIXME). This file defines WHEN and HOW
6
+ # to refactor — not the thresholds themselves.
7
+
8
+ ## Invariants — BLOCK on violation
9
+
10
+ ### Before touching any existing file
11
+ Check the file against `code-quality.md` hard limits before adding code.
12
+ If the file already violates limits:
13
+ 1. Do NOT add new code to it
14
+ 2. Refactor the file to compliance first
15
+ 3. THEN make the intended change
16
+ 4. Commit the refactor separately from the feature
17
+
18
+ This is mandatory. Adding to an already-broken file compounds debt exponentially.
19
+
20
+ ### Commit refactor separately from feature
21
+ - Refactoring commits use `refactor(scope):` prefix
22
+ - Feature commits use `feat(scope):` prefix
23
+ - Never mix structural changes and behavior changes in one commit
24
+ - Rationale: reviewers cannot distinguish "moved code" from "changed behavior" in a mixed diff
25
+
26
+ ### Copy-paste detection
27
+ If you find yourself copying 3+ lines from elsewhere in the same codebase: stop.
28
+ Extract a shared function in a common location.
29
+ Duplication is the root of divergent behavior bugs.
30
+
31
+ ## Conventions — WARN on violation
32
+
33
+ ### The QUALITY comment convention
34
+ When you encounter a known violation in code you are NOT tasked with fixing:
35
+ ```
36
+ // QUALITY: function exceeds 30 lines — refactor tracked in #123
37
+ ```
38
+
39
+ Rules for QUALITY comments:
40
+ - QUALITY: is the ONLY allowed debt marker. `TODO`, `FIXME`, and `HACK` are banned (see `code-quality.md`).
41
+ - Every QUALITY comment MUST include a tracking reference (issue number, ADR, or ticket).
42
+ - QUALITY comments are allowed in commits — unlike TODO/FIXME which are not.
43
+ - A QUALITY comment is NOT a license to defer indefinitely. It is a documented acknowledgment.
44
+
45
+ ### Refactor vs rewrite decision gate
46
+ - **Refactor** (preferred): same behavior, improved structure. Small, safe, incremental.
47
+ - **Rewrite**: new behavior or complete structural replacement.
48
+
49
+ If >50% of a file needs changing during a feature task:
50
+ 1. Stop. Do not incrementally refactor to the point of a full rewrite.
51
+ 2. File an issue for the rewrite.
52
+ 3. Complete the minimum viable refactor for the current feature.
53
+ 4. Propose the rewrite as a separate milestone with its own plan.
54
+
55
+ Never rewrite during a feature task without an explicit plan.
56
+
57
+ ## Removal Condition
58
+ Remove when automated refactoring tools (e.g., language-specific AST transforms)
59
+ handle pre-check validation and commit separation automatically.
@@ -0,0 +1,122 @@
1
+ # Writing Quality — Prose Generation Constraints
2
+ # Scope: All prose output — design docs, ADRs, READMEs, specs, PR descriptions,
3
+ # commit messages, code comments, status reports
4
+ # Always active during prose generation
5
+
6
+ ## The Prime Directive for Prose
7
+ Write for the engineer reading this at 11pm during an incident.
8
+ They have 90 seconds. Every word must earn its place.
9
+
10
+ ## Invariants — BLOCK on violation
11
+
12
+ ### Sentence limits
13
+ - Maximum 30 words per sentence. Count before writing long sentences.
14
+ - Maximum 5 sentences per paragraph.
15
+ - One idea per paragraph.
16
+
17
+ ### Fluff kill list — never write these words or phrases
18
+ leverage (use: use), utilize (use: use), facilitate (use: enable, allow, help),
19
+ moving forward, going forward, at this point in time, comprehensive solution,
20
+ robust solution, seamlessly, cutting-edge, best-in-class,
21
+ in order to (use: to), due to the fact that (use: because),
22
+ at the end of the day, synergy, holistic, empower, streamline
23
+
24
+ For additional banned AI-filler phrases, see `px-communication-standards` skill.
25
+ That skill covers: "Certainly!", "Absolutely!", "Great question!", "I'd be happy to",
26
+ "It's worth noting that", "In conclusion", "To summarize the above".
27
+ Both lists are enforced. Neither is optional.
28
+
29
+ ### Voice on decisions
30
+ - Active voice on decisions: "we decided" not "it was decided"
31
+ - Active voice on architecture: "this service handles X" not "X is handled by"
32
+ - Reserve passive voice for describing states: "the cache is invalidated when..."
33
+
34
+ ### Hedging on decided things
35
+ - Decided things use "will", not "should" or "might"
36
+ - Uncertain things are labeled explicitly: "open question:", "to be decided:"
37
+ - Never hedge silently. If you are uncertain, say so.
38
+
39
+ ## Document Structure — Mandatory Templates
40
+
41
+ ### Design Doc (filename: DESIGN-*.md or *-design.md)
42
+ Required sections — none optional, none empty:
43
+
44
+ #### Problem
45
+ - What is broken, missing, or painful? Past tense. Specific.
46
+ - "The auth service does not rate-limit failed login attempts" — GOOD
47
+ - "We need better authentication" — BAD (not specific, not a problem statement)
48
+
49
+ #### Decision
50
+ - What are we building? Active voice. One paragraph.
51
+ - State what this is AND what it is NOT (explicit scope boundary).
52
+
53
+ #### Tradeoffs
54
+ - Minimum 2 items. For each: what we gain AND what we give up.
55
+ - Not "pros and cons of the overall approach" — tradeoffs of THIS decision vs alternatives.
56
+
57
+ #### Acceptance Criteria
58
+ - Verifiable statements. Observable outcomes. Present tense.
59
+ - GOOD: "The login endpoint returns 429 after 5 failed attempts within 60 seconds"
60
+ - BAD: "The system handles failed logins correctly"
61
+ - BAD: "Improved security posture"
62
+
63
+ ### ADR (filename: ADR-NNN-*.md)
64
+ Required fields in this order:
65
+ ```
66
+ # ADR-NNN: {title}
67
+ Status: Proposed | Accepted | Deprecated | Superseded by ADR-NNN
68
+ Date: YYYY-MM-DD
69
+
70
+ ## Context
71
+ {past tense — what situation forced this decision}
72
+
73
+ ## Decision
74
+ {active voice — what we decided}
75
+
76
+ ## Consequences
77
+ ### Positive
78
+ - {at least one}
79
+ ### Negative
80
+ - {at least one — if no negatives, the decision is not analyzed}
81
+ ```
82
+
83
+ ### README (filename: README.md)
84
+ Required sections:
85
+ - First paragraph: what does this do (3 sentences max, no jargon)
86
+ - `## Install` or `## Setup` with exact commands
87
+ - `## Run` with exact commands — no `{placeholder}` in code blocks
88
+ - `## Test` with exact commands
89
+
90
+ ### PR Description
91
+ Required sections:
92
+ - **What**: one sentence — what changed
93
+ - **Why**: one sentence — why this was needed
94
+ - **How to verify**: exact steps a reviewer takes to confirm it works
95
+ - **Breaking changes**: explicit "None" if none — do not omit
96
+
97
+ ## Commit Messages
98
+ Format: `{type}({scope}): {what changed in imperative mood}`
99
+
100
+ Types: feat, fix, refactor, test, docs, chore, perf, ci
101
+ Scope: the module, package, or subsystem changed
102
+ Subject: present tense imperative — "add retry logic" not "added retry logic"
103
+
104
+ 50-char subject limit. 72-char body line limit if body is present.
105
+ Body explains WHY the change was needed, not what the diff shows.
106
+
107
+ ## Code Comments
108
+ - WHY not WHAT. The code shows what.
109
+ - GOOD: `// retry 3x — upstream returns 503 on cold start, recovers within 2s`
110
+ - BAD: `// increment counter`
111
+ - Zero tolerance for TODO/FIXME/HACK in committed code.
112
+ Use `// QUALITY: {issue} — tracked in #{issue-number}` if deferring.
113
+ See `refactor-triggers.md` for the QUALITY comment convention.
114
+
115
+ ## Cross-References
116
+ - Document-level formatting (proposals, status reports, executive summaries): see `px-communication-standards` skill
117
+ - Commit standards and git workflow: see `git-workflow.md`
118
+ - Code comment rules: see `code-quality.md` § On comments
119
+
120
+ ## Removal Condition
121
+ Remove when a prose linter (Vale or equivalent) runs as a generation-time hook
122
+ on all markdown and prose output.
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: px-complexity-audit
3
+ disable-model-invocation: true
4
+ description: "Codebase debt scanner. Ranks files by complexity score (size, nesting, debt markers, generic names). Use at sprint start, before major features, or quarterly. Outputs heat map and refactor targets."
5
+ ---
6
+
7
+ # px-complexity-audit — Codebase Debt Scanner
8
+
9
+ ## Purpose
10
+
11
+ Scans the existing codebase for accumulated technical debt.
12
+ Outputs a ranked heat map of files needing attention.
13
+ Use before starting major feature work or at sprint boundaries.
14
+
15
+ ## When To Use
16
+
17
+ 1. Sprint start: identify cleanup targets before new work begins
18
+ 2. Pre-feature: assess the health of files you are about to modify
19
+ 3. Quarterly: full codebase scan, results written to vault
20
+ 4. On-demand: `/px-complexity-audit {directory}` for targeted scan
21
+
22
+ ## What It Scans
23
+
24
+ ### File-level metrics
25
+
26
+ ```bash
27
+ FILE_LINES=$(wc -l < "$f")
28
+ TODO_COUNT=$(grep -cE 'TODO|FIXME|HACK|QUALITY:' "$f" || echo 0)
29
+ FUNC_COUNT=$(grep -cE '(func |def |function |const .* = )' "$f" || echo 0)
30
+ DEEP_NEST=$(grep -cE '^\s{16,}\S|^\t{4,}\S' "$f" || echo 0)
31
+ GENERIC_NAMES=$(grep -oE '\b(data|result|info|temp|tmp|obj|val|item|stuff|thing|ret|res)\b' "$f" | wc -l || echo 0)
32
+ ```
33
+
34
+ ### Debt score formula
35
+
36
+ Each file receives a composite score (higher = more urgent):
37
+
38
+ ```
39
+ debt_score = (
40
+ (file_lines / 300 * 30) + # Over size limit: 30 points at 300 lines
41
+ (todo_count * 10) + # 10 points per debt marker
42
+ (deep_nest_lines * 5) + # 5 points per deeply nested line
43
+ (generic_name_count * 2) + # 2 points per generic name
44
+ (longest_function / 30 * 20) # Over function limit: 20 points at 30 lines
45
+ )
46
+ ```
47
+
48
+ Thresholds:
49
+
50
+ - Score 0-20: CLEAN — no action needed
51
+ - Score 21-50: WATCH — consider cleanup if touching this file
52
+ - Score 51-80: REFACTOR — clean up before adding features
53
+ - Score 81+: CRITICAL — stop and refactor now
54
+
55
+ ### Potential dead code detection
56
+
57
+ ```bash
58
+ for func_name in $(grep -ohE '(func|def|function)\s+\w+' "$f" | awk '{print $2}'); do
59
+ refs=$(rg -l "$func_name" --type-add 'code:*.{go,ts,py,js,rs,java}' -t code . | grep -v "$f" | wc -l || echo 0)
60
+ if [[ "$refs" -eq 0 ]]; then
61
+ echo "POTENTIAL_DEAD: $func_name in $f (0 external references)"
62
+ fi
63
+ done
64
+ ```
65
+
66
+ ## Output Format
67
+
68
+ ### Heat Map (terminal output)
69
+
70
+ ```
71
+ ━━━ COMPLEXITY AUDIT ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
72
+ Scanned: 47 files | CLEAN: 31 | WATCH: 9 | REFACTOR: 5 | CRIT: 2
73
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
74
+
75
+ TOP 5 REFACTOR TARGETS
76
+
77
+ Rank | File | Score | Primary Issue
78
+ ─────┼─────────────────────────────┼───────┼────────────────────
79
+ 1 | services/auth/handler.go | 94 | 342 lines, 4 TODOs
80
+ 2 | services/billing/calc.py | 87 | 60-line function
81
+ 3 | handlers/api/v2/users.ts | 73 | 5-level nesting
82
+ 4 | lib/cache/redis.go | 58 | 12 generic names
83
+ 5 | cmd/worker/process.go | 52 | 3 TODOs, 280 lines
84
+
85
+ Estimated effort: ~4 hours for top 5
86
+ ```
87
+
88
+ ### Effort estimation heuristic
89
+
90
+ | Action | Estimated time |
91
+ | ------ | -------------- |
92
+ | Split a 300+ line file | 30-45 min |
93
+ | Extract a 30+ line function | 15-20 min |
94
+ | Flatten deep nesting | 10-15 min per function |
95
+ | Rename generic variables | 5-10 min per file |
96
+ | Address a TODO with ticket | 5 min (triage) or 30+ min (fix) |
97
+
98
+ ### Vault output
99
+
100
+ When run with `--write-vault` or during quarterly scan:
101
+
102
+ ```
103
+ Output path: {vault_path}/specs/debt-audit-{YYYY-MM-DD}.md
104
+ ```
105
+
106
+ Contents:
107
+
108
+ - Full ranked file list with scores
109
+ - Top 5 refactor targets with specific actions
110
+ - Trend comparison if previous audit exists (score delta per file)
111
+ - Recommended sprint allocation (hours) for debt reduction
112
+
113
+ ## Limitations
114
+
115
+ - Dead code detection is heuristic — false positives on exported/public APIs
116
+ - Nesting depth uses indentation as proxy — may miscount in some styles
117
+ - Does not analyze cyclomatic complexity (would require AST parsing per language)
118
+ - Effort estimates are rough guides, not commitments
@@ -10,7 +10,10 @@ You are running a structured technical discovery.
10
10
  - Read vault_path from `~/.claude/praxis.config.json`
11
11
  - What decision needs to be made? (one sentence)
12
12
  - What are the constraints? (compliance, performance, compatibility, cost)
13
- - What is already known? (run `obsidian search query="{topic}" limit=5`)
13
+ - What is already known? Search vault using configured backend:
14
+ - If `obsidian`: run `obsidian search query="{topic}" limit=5`
15
+ - If `ripgrep`: run `rg --files-with-matches "{topic}" {vault_path}/`
16
+ - If vault search fails: proceed without blocking
14
17
 
15
18
  **Step 2 — Research options**
16
19
  - Identify 2-4 viable options. For each:
@@ -23,7 +23,10 @@ Do NOT present a template or form. Let them talk.
23
23
 
24
24
  **Step 3 — Search for related work**
25
25
  After the user describes the task, search vault for prior art:
26
- Run: `obsidian search query="{topic}" limit=5`
26
+ Read `vault_backend` from `~/.claude/praxis.config.json`.
27
+ - If `obsidian`: run `obsidian search query="{topic}" limit=5`
28
+ - If `ripgrep`: run `rg --files-with-matches "{topic}" {vault_path}/`
29
+ - If vault search fails (e.g., Obsidian not running): warn and proceed without blocking.
27
30
  If related specs, plans, or research exist: mention them briefly.
28
31
  If nothing exists: proceed silently.
29
32