@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.
- package/base/CLAUDE.md +14 -1
- package/base/hooks/auto-format.sh +1 -1
- package/base/hooks/dep-audit.sh +1 -1
- package/base/hooks/file-guard.sh +3 -3
- package/base/hooks/recursion-guard.sh +7 -1
- package/base/hooks/session-data-collect.sh +1 -1
- package/base/hooks/vault-checkpoint.sh +5 -5
- package/base/rules/code-excellence.md +22 -0
- package/base/rules/coding.md +16 -0
- package/base/rules/observable-code.md +87 -0
- package/base/rules/refactor-triggers.md +59 -0
- package/base/rules/writing-quality.md +122 -0
- package/base/skills/px-complexity-audit/SKILL.md +118 -0
- package/base/skills/px-discover/SKILL.md +4 -1
- package/base/skills/px-discuss/SKILL.md +4 -1
- package/base/skills/px-doc-lint/SKILL.md +107 -0
- package/base/skills/px-prose-review/SKILL.md +96 -0
- package/base/skills/px-quality-gate/SKILL.md +182 -0
- package/base/skills/px-risk/SKILL.md +4 -1
- package/base/skills/px-scaffold-new/SKILL.md +16 -14
- package/base/skills/px-session-retro/SKILL.md +1 -1
- package/base/skills/px-spec/SKILL.md +6 -2
- package/base/skills/px-verify/SKILL.md +2 -1
- package/bin/praxis.js +27 -6
- package/kits/api/install.sh +1 -1
- package/kits/api/teardown.sh +1 -1
- package/kits/code-quality/hooks/generate-baseline.sh +1 -1
- package/kits/code-quality/hooks/post-commit.sh +3 -2
- package/kits/code-quality/hooks/pre-push.sh +15 -15
- package/kits/code-quality/install.sh +1 -1
- package/kits/code-quality/teardown.sh +3 -3
- package/kits/data/install.sh +1 -1
- package/kits/data/teardown.sh +1 -1
- package/kits/infrastructure/install.sh +1 -1
- package/kits/infrastructure/teardown.sh +1 -1
- package/kits/security/install.sh +1 -1
- package/kits/security/teardown.sh +1 -1
- package/kits/web-designer/install.sh +1 -1
- package/kits/web-designer/teardown.sh +1 -1
- package/package.json +1 -1
- package/scripts/health-check.sh +21 -15
- package/scripts/install-tools.sh +5 -5
- package/scripts/lint-harness.sh +1 -1
- package/scripts/onboard-mcp.sh +1 -1
- package/scripts/test-harness.sh +1 -1
- 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 (
|
|
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
|
|
package/base/hooks/dep-audit.sh
CHANGED
|
@@ -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 -
|
|
5
|
+
set -euo pipefail
|
|
6
6
|
trap 'exit 0' ERR
|
|
7
7
|
|
|
8
8
|
INPUT=$(cat)
|
package/base/hooks/file-guard.sh
CHANGED
|
@@ -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
|
-
|
|
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 -
|
|
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 -
|
|
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-%
|
|
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.
|
package/base/rules/coding.md
CHANGED
|
@@ -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?
|
|
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
|
-
|
|
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
|
|