@esoteric-logic/praxis-harness 2.8.0 → 2.9.1

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 (52) hide show
  1. package/base/CLAUDE.md +11 -2
  2. package/base/configs/ci/lint-stack.yml +19 -109
  3. package/base/configs/registry.json +1 -5
  4. package/base/hooks/auto-format.sh +1 -0
  5. package/base/hooks/dep-audit.sh +20 -7
  6. package/base/hooks/session-data-collect.sh +1 -0
  7. package/base/hooks/settings-hooks.json +0 -13
  8. package/base/hooks/vault-checkpoint.sh +1 -2
  9. package/base/lib/kit-check.sh +42 -0
  10. package/base/lib/output.sh +38 -0
  11. package/base/rules/code-quality.md +56 -0
  12. package/base/rules/coding.md +15 -110
  13. package/base/skills/code-excellence.md +69 -0
  14. package/base/skills/engineering-judgment.md +71 -0
  15. package/base/skills/px-code-gc/SKILL.md +2 -2
  16. package/base/skills/px-deepsource-coverage/SKILL.md +48 -0
  17. package/base/skills/px-deepsource-review/SKILL.md +50 -0
  18. package/base/skills/px-deepsource-setup/SKILL.md +56 -0
  19. package/base/skills/px-pre-commit-lint/SKILL.md +1 -2
  20. package/base/skills/px-scaffold-new/references/repo-CLAUDE-md-template.md +1 -1
  21. package/base/skills/px-ship/SKILL.md +1 -1
  22. package/base/skills/px-verify/SKILL.md +2 -2
  23. package/base/skills/self-verify.md +78 -0
  24. package/bin/praxis-preflight.sh +6 -9
  25. package/bin/praxis.js +3 -3
  26. package/kits/api/install.sh +3 -16
  27. package/kits/code-quality/KIT.md +55 -0
  28. package/kits/code-quality/configs/checks-registry.json +35 -0
  29. package/kits/code-quality/configs/thresholds.json +36 -0
  30. package/kits/code-quality/hooks/generate-baseline.sh +30 -0
  31. package/kits/code-quality/hooks/post-commit.sh +28 -0
  32. package/kits/code-quality/hooks/pre-push.sh +127 -0
  33. package/kits/code-quality/install.sh +68 -0
  34. package/kits/code-quality/manifest.json +27 -0
  35. package/kits/code-quality/skills/over-engineering.md +72 -0
  36. package/kits/code-quality/skills/performance-review.md +65 -0
  37. package/kits/code-quality/skills/self-review.md +55 -0
  38. package/kits/code-quality/skills/structural-review.md +57 -0
  39. package/kits/code-quality/teardown.sh +21 -0
  40. package/kits/data/install.sh +6 -19
  41. package/kits/infrastructure/install.sh +2 -20
  42. package/kits/security/commands/security-audit.md +1 -1
  43. package/kits/security/install.sh +5 -18
  44. package/kits/security/teardown.sh +1 -1
  45. package/package.json +1 -1
  46. package/scripts/install-tools.sh +2 -2
  47. package/scripts/onboard-mcp.sh +3 -18
  48. package/scripts/test-harness.sh +5 -13
  49. package/base/configs/linters/.pre-commit-config.yaml +0 -63
  50. package/base/configs/linters/semgrep.yml +0 -65
  51. package/base/hooks/post-session-lint.sh +0 -44
  52. package/base/hooks/quality-check.sh +0 -202
package/base/CLAUDE.md CHANGED
@@ -128,24 +128,33 @@ Kits activate via `/px-kit:<n>` slash command. Kits are idempotent — double-ac
128
128
  | infrastructure | `/px-kit:infrastructure` | Terraform → Azure → GitHub Actions → compliance |
129
129
  | api | `/px-kit:api` | RESTful conventions → OpenAPI specs → contract testing |
130
130
  | security | `/px-kit:security` | Threat modeling → IAM review → OWASP audit |
131
+ | code-quality | `/px-kit:code-quality` | SAST + secrets + SCA + IaC gate → AI review (over-engineering, smells, structure) |
131
132
  | data | `/px-kit:data` | Schema design → migration planning → query optimization |
132
133
 
133
134
  Kit manifests live in `~/.claude/kits/<name>/KIT.md`.
134
135
 
135
136
  ## Rules Registry — Load on Demand Only
136
137
 
137
- ### Universal — always active (8 rules)
138
+ ### Universal — always active (9 rules)
138
139
  | File | Purpose |
139
140
  |------|---------|
140
141
  | `~/.claude/rules/profile.md` | Who the user is, identities, working style |
141
142
  | `~/.claude/rules/execution-loop.md` | SPEC/PLAN/VALIDATE loop enforcement |
142
- | `~/.claude/rules/coding.md` | Code quality, security, complexity thresholds, Context7 mandate |
143
+ | `~/.claude/rules/coding.md` | Context7 mandate, tool preferences, quality architecture reference |
144
+ | `~/.claude/rules/code-quality.md` | Layer 2: Active constraints — hard limits during generation |
143
145
  | `~/.claude/rules/git-workflow.md` | Commits, branches, identity verification, pre-commit checks |
144
146
  | `~/.claude/rules/vault.md` | Second brain integration — vault backend, file purposes |
145
147
  | `~/.claude/rules/context-management.md` | Context anti-rot, phase scoping, context reset protocol |
146
148
  | `~/.claude/rules/memory-boundary.md` | Auto-memory boundary, MEMORY.md cap, dream integration |
147
149
  | `~/.claude/rules/security-posture.md` | Sandbox model, credential protection, protected paths |
148
150
 
151
+ ### Skills — loaded at session start
152
+ | File | Purpose |
153
+ |------|---------|
154
+ | `~/.claude/skills/code-excellence.md` | Layer 1: Principles — shapes reasoning about code |
155
+ | `~/.claude/skills/engineering-judgment.md` | Layer 1: Meta-reasoning — principal engineer decision framework |
156
+ | `~/.claude/skills/self-verify.md` | Layer 3: Self-verification protocol — proves correctness before commit |
157
+
149
158
  ### Scoped — load only when paths match
150
159
  | File | Loads when |
151
160
  |------|------------|
@@ -1,7 +1,7 @@
1
- # Polyglot Lint Stack — 3-Layer CI Template
1
+ # Lint Stack — CI Template
2
2
  # Copy to: .github/workflows/lint-stack.yml
3
- # Conditional: each tool runs only if its language files exist in the repo.
4
- # Pin actions to SHA update hashes when upgrading versions.
3
+ # DeepSource handles comprehensive analysis via GitHub app integration.
4
+ # This workflow provides basic file hygiene checks only.
5
5
 
6
6
  name: Lint Stack
7
7
  on:
@@ -10,117 +10,27 @@ on:
10
10
 
11
11
  permissions:
12
12
  contents: read
13
- pull-requests: write
14
13
 
15
14
  jobs:
16
- # ─────────────────────────────────────────────
17
- # LAYER 1: Fast Feedback (~10s per tool)
18
- # ─────────────────────────────────────────────
19
- lint:
20
- name: L1 — Lint + Format
15
+ hygiene:
16
+ name: File Hygiene
21
17
  runs-on: ubuntu-latest
22
18
  steps:
23
19
  - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24
20
 
25
- # Python Ruff
26
- - name: Ruff check
27
- if: hashFiles('**/*.py') != ''
28
- uses: astral-sh/ruff-action@9700c1666704e06e2cf8f9046755e3dfc6297e40 # v3.2.1
29
- with:
30
- args: "check"
31
- - name: Ruff format check
32
- if: hashFiles('**/*.py') != ''
33
- uses: astral-sh/ruff-action@9700c1666704e06e2cf8f9046755e3dfc6297e40 # v3.2.1
34
- with:
35
- args: "format --check"
36
-
37
- # JS/TS — Biome
38
- - name: Setup Biome
39
- if: hashFiles('**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx') != ''
40
- uses: biomejs/setup-biome@1cbe33ead22c7a2fded3b52fa2893611c815c3d2 # v2.5.0
41
- - name: Biome CI
42
- if: hashFiles('**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx') != ''
43
- run: biome ci .
44
-
45
- # Go — golangci-lint
46
- - name: golangci-lint
47
- if: hashFiles('go.mod') != ''
48
- uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0
49
- with:
50
- version: v2.1
51
-
52
- # Rust — Clippy
53
- - name: Setup Rust toolchain
54
- if: hashFiles('Cargo.toml') != ''
55
- uses: dtolnay/rust-toolchain@56f84321dbccf38fb67ce29ab63e4754056677e0 # stable
56
- with:
57
- toolchain: stable
58
- components: clippy, rustfmt
59
- - name: Clippy
60
- if: hashFiles('Cargo.toml') != ''
61
- run: cargo clippy --all-targets --all-features -- -D warnings
62
- - name: rustfmt check
63
- if: hashFiles('Cargo.toml') != ''
64
- run: cargo fmt --all -- --check
65
-
66
- # Shell — ShellCheck
67
- - name: ShellCheck
68
- if: hashFiles('**/*.sh') != ''
21
+ - name: Check for merge conflict markers
69
22
  run: |
70
- sudo apt-get install -y shellcheck
71
- find . -name '*.sh' -not -path './node_modules/*' -not -path './vendor/*' | xargs shellcheck -s bash
72
-
73
- # ─────────────────────────────────────────────
74
- # LAYER 2: Quality Gates (~2min)
75
- # ─────────────────────────────────────────────
76
- security-scan:
77
- name: L2 — Semgrep
78
- runs-on: ubuntu-latest
79
- needs: lint
80
- steps:
81
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
82
- - uses: semgrep/semgrep-action@713efdd345ae26c72e79b5b32927be8e0e6bab83 # v1
83
- with:
84
- config: >-
85
- p/default
86
- p/secrets
87
- p/owasp-top-ten
88
- env:
89
- SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
23
+ if git grep -rn '<<<<<<< \|>>>>>>> ' -- ':!*.yml' ':!*.yaml'; then
24
+ echo "::error::Merge conflict markers found"
25
+ exit 1
26
+ fi
90
27
 
91
- # Uncomment to add SonarQube quality gate (requires self-hosted server)
92
- # sonarqube:
93
- # name: L2 SonarQube
94
- # runs-on: ubuntu-latest
95
- # needs: lint
96
- # steps:
97
- # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
98
- # with:
99
- # fetch-depth: 0
100
- # - uses: SonarSource/sonarqube-scan-action@0e1a25e90571a34e2ec5c72ee40ba45cc73a1e6e # v4
101
- # env:
102
- # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
103
- # SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
104
- # - uses: SonarSource/sonarqube-quality-gate-action@dc2f7b0dd95544cd550de3066f25f47e3fc20894 # v1.1.0
105
- # timeout-minutes: 5
106
- # env:
107
- # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
108
-
109
- # ─────────────────────────────────────────────
110
- # LAYER 3: AI Review (~2min, optional)
111
- # ─────────────────────────────────────────────
112
- # Uncomment to enable AI-powered PR review.
113
- # Requires OPENAI_API_KEY secret or self-hosted Ollama.
114
- #
115
- # ai-review:
116
- # name: L3 — AI Review
117
- # runs-on: ubuntu-latest
118
- # needs: [security-scan]
119
- # steps:
120
- # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
121
- # - uses: Codium-ai/pr-agent@main
122
- # env:
123
- # OPENAI_KEY: ${{ secrets.OPENAI_API_KEY }}
124
- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
125
- # with:
126
- # command: review
28
+ - name: Check for large files
29
+ run: |
30
+ find . -type f -size +500k \
31
+ -not -path './.git/*' \
32
+ -not -path './node_modules/*' \
33
+ -not -path './vendor/*' \
34
+ -not -path './.terraform/*' | head -20 | while read -r f; do
35
+ echo "::warning file=$f::File exceeds 500KB"
36
+ done
@@ -26,16 +26,13 @@
26
26
  {"name": "gh", "minVersion": "2.0.0", "install": "brew install gh"}
27
27
  ],
28
28
  "optional": [
29
- {"name": "trufflehog", "feature": "secret-scanning", "install": "brew install trufflehog"},
30
- {"name": "gitleaks", "feature": "secret-scanning", "install": "brew install gitleaks"},
29
+ {"name": "deepsource", "feature": "code-analysis", "install": "curl -fsSL https://cli.deepsource.com/install | sh"},
31
30
  {"name": "osv-scanner", "feature": "dep-audit", "install": "go install github.com/google/osv-scanner/cmd/osv-scanner@latest"},
32
31
  {"name": "pip-audit", "feature": "dep-audit-python", "install": "pip install pip-audit"},
33
32
  {"name": "docker", "feature": "docker-sandbox", "install": "brew install --cask docker"},
34
33
  {"name": "biome", "feature": "lint-js", "install": "npm install -g @biomejs/biome"},
35
34
  {"name": "ruff", "feature": "lint-python", "install": "pip install ruff"},
36
- {"name": "semgrep", "feature": "security-scan", "install": "pip install semgrep"},
37
35
  {"name": "markdownlint", "feature": "lint-markdown", "install": "npm install -g markdownlint-cli"},
38
- {"name": "pre-commit", "feature": "pre-commit-hooks", "install": "pip install pre-commit"},
39
36
  {"name": "golangci-lint", "feature": "lint-go", "install": "brew install golangci-lint"},
40
37
  {"name": "rustfmt", "feature": "format-rust", "install": "rustup component add rustfmt"},
41
38
  {"name": "clippy", "feature": "lint-rust", "install": "rustup component add clippy"}
@@ -104,7 +101,6 @@
104
101
  {"path": "base/hooks/file-guard.sh", "event": "PreToolUse", "matcher": "Write|Edit|MultiEdit"},
105
102
  {"path": "base/hooks/identity-check.sh", "event": "PreToolUse", "matcher": "Bash"},
106
103
  {"path": "base/hooks/credential-guard.sh", "event": "PreToolUse", "matcher": "Bash"},
107
- {"path": "base/hooks/quality-check.sh", "event": "PostToolUse", "matcher": "Write|Edit|MultiEdit"},
108
104
  {"path": "base/hooks/session-data-collect.sh", "event": "Stop", "matcher": ""}
109
105
  ],
110
106
  "optional": [
@@ -2,6 +2,7 @@
2
2
  # PostToolUse hook — auto-formats files after edit.
3
3
  # Always exits 0 (advisory, never blocks).
4
4
  set -uo pipefail
5
+ trap 'exit 0' ERR
5
6
 
6
7
  INPUT=$(cat)
7
8
  FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null)
@@ -2,7 +2,8 @@
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 -euo pipefail
5
+ set -uo pipefail
6
+ trap 'exit 0' ERR
6
7
 
7
8
  INPUT=$(cat)
8
9
  FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null)
@@ -20,28 +21,40 @@ case "$BASENAME" in
20
21
  package.json)
21
22
  ECOSYSTEM="npm"
22
23
  if command -v npm &>/dev/null && [[ -f "$DIR/package-lock.json" || -f "$DIR/node_modules/.package-lock.json" ]]; then
23
- AUDIT_RESULT=$(cd "$DIR" && npm audit --audit-level=high --json 2>/dev/null || true)
24
+ # npm audit exits non-zero when vulnerabilities exist — capture output regardless
25
+ AUDIT_RESULT=$(cd "$DIR" && npm audit --audit-level=high --json 2>/dev/null) || {
26
+ if [[ -n "$AUDIT_RESULT" ]]; then
27
+ : # non-zero with output = vulnerabilities found (expected)
28
+ else
29
+ echo "DEP-AUDIT (npm): audit command failed" >&2
30
+ fi
31
+ }
24
32
  fi
25
33
  ;;
26
34
  go.mod)
27
35
  ECOSYSTEM="go"
28
36
  if command -v govulncheck &>/dev/null; then
29
- AUDIT_RESULT=$(cd "$DIR" && govulncheck -json ./... 2>/dev/null || true)
37
+ AUDIT_RESULT=$(cd "$DIR" && govulncheck -json ./... 2>/dev/null) || {
38
+ [[ -z "$AUDIT_RESULT" ]] && echo "DEP-AUDIT (go): govulncheck failed" >&2
39
+ }
30
40
  elif command -v go &>/dev/null; then
31
- # Fallback: at least check for known issues via go list
32
- AUDIT_RESULT=$(cd "$DIR" && go list -m -json all 2>/dev/null | head -c 5000 || true)
41
+ AUDIT_RESULT=$(cd "$DIR" && go list -m -json all 2>/dev/null | head -c 5000) || AUDIT_RESULT=""
33
42
  fi
34
43
  ;;
35
44
  requirements.txt|pyproject.toml)
36
45
  ECOSYSTEM="python"
37
46
  if command -v pip-audit &>/dev/null; then
38
- AUDIT_RESULT=$(cd "$DIR" && pip-audit --format=json 2>/dev/null || true)
47
+ AUDIT_RESULT=$(cd "$DIR" && pip-audit --format=json 2>/dev/null) || {
48
+ [[ -z "$AUDIT_RESULT" ]] && echo "DEP-AUDIT (python): pip-audit failed" >&2
49
+ }
39
50
  fi
40
51
  ;;
41
52
  Cargo.toml)
42
53
  ECOSYSTEM="rust"
43
54
  if command -v cargo-audit &>/dev/null; then
44
- AUDIT_RESULT=$(cd "$DIR" && cargo audit --json 2>/dev/null || true)
55
+ AUDIT_RESULT=$(cd "$DIR" && cargo audit --json 2>/dev/null) || {
56
+ [[ -z "$AUDIT_RESULT" ]] && echo "DEP-AUDIT (rust): cargo-audit failed" >&2
57
+ }
45
58
  fi
46
59
  ;;
47
60
  *)
@@ -2,6 +2,7 @@
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
4
  set -uo pipefail
5
+ trap 'exit 0' ERR
5
6
 
6
7
  CONFIG_FILE="$HOME/.claude/praxis.config.json"
7
8
 
@@ -39,15 +39,6 @@
39
39
  }
40
40
  ],
41
41
  "PostToolUse": [
42
- {
43
- "matcher": "Write|Edit|MultiEdit",
44
- "hooks": [
45
- {
46
- "type": "command",
47
- "command": "bash ~/.claude/hooks/quality-check.sh"
48
- }
49
- ]
50
- },
51
42
  {
52
43
  "matcher": "Write|Edit|MultiEdit",
53
44
  "hooks": [
@@ -62,10 +53,6 @@
62
53
  {
63
54
  "matcher": "",
64
55
  "hooks": [
65
- {
66
- "type": "command",
67
- "command": "bash ~/.claude/hooks/post-session-lint.sh"
68
- },
69
56
  {
70
57
  "type": "prompt",
71
58
  "prompt": "Run the project test suite. Read CLAUDE.md ## Commands for the test command. If no test command defined, respond {ok:true}. Run tests. If all pass: respond {ok:true}. If tests fail: respond {ok:false, reason:'Tests failing: <summary>'}. Do not fix — only report."
@@ -2,6 +2,7 @@
2
2
  # PreCompact hook — writes minimal checkpoint to vault before context compaction.
3
3
  # Always exits 0 (advisory, never blocks compaction).
4
4
  set -uo pipefail
5
+ trap 'exit 0' ERR
5
6
 
6
7
  CONFIG_FILE="$HOME/.claude/praxis.config.json"
7
8
 
@@ -23,8 +24,6 @@ CHECKPOINT_FILE="$PLANS_DIR/$DATE-compact-checkpoint.md"
23
24
 
24
25
  BRANCH=$(git --no-pager rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
25
26
  LAST_COMMIT=$(git --no-pager log --oneline -1 2>/dev/null || echo "no commits")
26
- PROJECT_DIR=$(basename "$PWD")
27
-
28
27
  STATUS_FILE="$VAULT_PATH/status.md"
29
28
  PROGRESS_FILE="$VAULT_PATH/claude-progress.json"
30
29
 
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ # ════════════════════════════════════════════════════════════════
3
+ # Praxis — Shared Kit Install Check
4
+ # Source this file in kit install.sh scripts for consistent
5
+ # tool-checking output and counters.
6
+ #
7
+ # Usage:
8
+ # source "$(dirname "$0")/../../base/lib/kit-check.sh"
9
+ # check "jq" "brew install jq"
10
+ # check "curl" "pre-installed on macOS/Linux"
11
+ # kit_check_summary
12
+ # ════════════════════════════════════════════════════════════════
13
+
14
+ KIT_CHECK_PASS=0
15
+ KIT_CHECK_TOTAL=0
16
+
17
+ check() {
18
+ local cmd="$1"
19
+ local install_hint="$2"
20
+ local optional="${3:-}"
21
+
22
+ KIT_CHECK_TOTAL=$((KIT_CHECK_TOTAL + 1))
23
+ if command -v "$cmd" &>/dev/null; then
24
+ echo " ✓ $cmd found ($(command -v "$cmd"))"
25
+ KIT_CHECK_PASS=$((KIT_CHECK_PASS + 1))
26
+ else
27
+ if [[ "$optional" == "optional" ]]; then
28
+ echo " ⚠ $cmd not found (optional)"
29
+ else
30
+ echo " ✗ $cmd not found"
31
+ fi
32
+ echo " Install: $install_hint"
33
+ fi
34
+ }
35
+
36
+ kit_check_summary() {
37
+ echo ""
38
+ echo " $KIT_CHECK_PASS/$KIT_CHECK_TOTAL tools found"
39
+ if [[ $KIT_CHECK_PASS -lt $KIT_CHECK_TOTAL ]]; then
40
+ echo " ⚠ Some tools missing. Install them before using kit commands."
41
+ fi
42
+ }
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # ═══════��════════════════════════════════════════════════════════
3
+ # Praxis — Shared Output Helpers
4
+ # Source this file instead of defining colors/helpers inline.
5
+ #
6
+ # Usage:
7
+ # source "$(dirname "$0")/../base/lib/output.sh"
8
+ # # or with absolute path:
9
+ # source "$HOME/.claude/lib/output.sh"
10
+ #
11
+ # Safe to source multiple times — guards against redefinition.
12
+ # ════��═══════════════════════════════════════════════════════════
13
+
14
+ # ─── Colors (skip if already set) ───
15
+ RED="${RED:-\033[0;31m}"
16
+ GREEN="${GREEN:-\033[0;32m}"
17
+ YELLOW="${YELLOW:-\033[0;33m}"
18
+ CYAN="${CYAN:-\033[0;36m}"
19
+ BOLD="${BOLD:-\033[1m}"
20
+ DIM="${DIM:-\033[2m}"
21
+ NC="${NC:-\033[0m}"
22
+
23
+ # ─── Output helpers (skip if already defined) ───
24
+ if ! declare -f ok &>/dev/null; then
25
+ ok() { echo -e " ${GREEN}✓${NC} $1"; }
26
+ fi
27
+ if ! declare -f warn &>/dev/null; then
28
+ warn() { echo -e " ${YELLOW}⚠${NC} $1"; }
29
+ fi
30
+ if ! declare -f fail &>/dev/null; then
31
+ fail() { echo -e " ${RED}✗${NC} $1"; }
32
+ fi
33
+ if ! declare -f step &>/dev/null; then
34
+ step() { echo -e "\n${CYAN}${BOLD}$1${NC}"; }
35
+ fi
36
+ if ! declare -f dim &>/dev/null; then
37
+ dim() { echo -e " ${DIM}$1${NC}"; }
38
+ fi
@@ -0,0 +1,56 @@
1
+ # Code Quality — Active Constraints
2
+
3
+ These rules are active during code generation. They are not reviewed after writing —
4
+ they shape what gets written in the first place.
5
+
6
+ ## Before writing any function
7
+ State in a single-line comment what this function does.
8
+ If you cannot write the comment in one sentence, split the function first.
9
+ The function name must be derivable from that comment.
10
+
11
+ ## Hard limits — never violate without explicit documented exception
12
+ - No function exceeds 30 lines of logic (blank lines and comments excluded)
13
+ - No block nesting deeper than 3 levels
14
+ - No function with more than 4 parameters — use an options/config object beyond 4
15
+ - No class with more than 5 public methods — split the class first
16
+ - No file with more than 300 lines — split the module first
17
+ - No `TODO` or `FIXME` committed — resolve inline or create a tracked issue with link in comment
18
+
19
+ ## Before introducing any abstraction (interface, base class, factory, wrapper)
20
+ Identify exactly 2 or more existing concrete use cases that require it.
21
+ They must exist in the current codebase, not in anticipated future requirements.
22
+ If only 1 use case exists, inline the logic and do not create the abstraction.
23
+
24
+ ## Before adding any new dependency
25
+ - Verify the standard library does not provide equivalent functionality
26
+ - Verify the package has had a commit within the last 6 months
27
+ - Pin to exact version in package manifest
28
+ - Add a comment above the import explaining why this dependency was chosen over alternatives
29
+
30
+ ## On every new public function or method
31
+ Write the JSDoc/docstring before writing the implementation.
32
+ The docstring must include: what it does, what each parameter is, what it returns, what it throws.
33
+ If you cannot write the docstring, you do not yet understand what you are building.
34
+
35
+ ## On error handling — no exceptions
36
+ - Every async function has explicit error handling (try/catch or .catch() or Result type)
37
+ - Every function that receives external input validates type, range, and format before use
38
+ - Every thrown error has a message that identifies: what failed, why it failed, what the caller should do
39
+ - Errors are never caught and silently ignored — log at minimum, re-throw if unhandled
40
+
41
+ ## On tests
42
+ - New public functions require tests before the PR is considered complete
43
+ - Tests assert behavior (outputs and side effects), not implementation (which internal functions were called)
44
+ - Each test covers exactly one scenario — no multi-scenario tests
45
+ - Test files mirror source file structure — `src/auth/login.ts` → `tests/auth/login.test.ts`
46
+
47
+ ## On comments
48
+ Write comments that explain WHY, not WHAT.
49
+ Delete any comment that restates what the code already says.
50
+ Write comments that capture: non-obvious decisions, external constraints, known limitations.
51
+
52
+ ## On naming
53
+ - No single-letter variables except loop indices (`i`, `j`, `k`) in tight loops of ≤5 lines
54
+ - No abbreviations unless they are universally understood domain terms (`id`, `url`, `api`)
55
+ - No generic names: `data`, `info`, `temp`, `result`, `obj`, `val`, `res`, `thing`, `stuff`
56
+ - Rename before committing. Names do not get "cleaned up later."
@@ -1,6 +1,5 @@
1
1
  # Coding — Universal Rules
2
2
  <!-- Universal — applies to ALL code regardless of language or stack -->
3
- <!-- Merged from coding.md + code-quality.md -->
4
3
 
5
4
  ---
6
5
 
@@ -9,132 +8,44 @@
9
8
  ### Documentation lookup before implementation
10
9
  - Before implementing anything that uses an external library, framework, or API:
11
10
  use Context7 to get current docs. Training data has a cutoff. Context7 does not.
12
- - Append "use context7" to any prompt involving a library not personally verified as current.
13
11
  - Never suggest a method, constructor, or API signature from memory for a library
14
12
  that releases frequently. Look it up first via Context7.
15
13
  - If Context7 is unavailable: state that docs could not be verified and flag the
16
14
  specific method/API as "unverified against current version."
17
15
 
18
- ### Error handling
19
- - Never silently swallow exceptions. Every catch block must either re-throw,
20
- log with context, or return a typed error.
21
- - No empty catch blocks. No fallback defaults unless explicitly asked.
22
- - Error messages MUST include context: request params, response body, status codes.
23
- - Use structured logging fields, not string interpolation.
24
- - External calls: retries with exponential backoff + warnings, then raise last error.
25
- - Validate response shape, not just status code — a 200 with error body is a silent failure.
26
- - Every function that can fail must have an explicit failure path.
27
- - Validate inputs at the boundary. Never assume callers pass correct data.
28
-
29
- ### No hardcoded values
30
- - No credentials, tokens, connection strings, or API keys inline. Ever.
31
- Use environment variables, Key Vault references, or parameter files.
32
- - No hardcoded paths specific to one machine. Use relative paths or env-derived roots.
33
- - No magic numbers without a named constant and a comment explaining the value.
34
-
35
- ### State and side effects
36
- - Pure functions where possible. If a function mutates state, its name must signal that.
37
- - Never mutate input parameters. Return new values.
38
- - Write pure functions — only modify return values, never inputs or global state.
39
-
40
- ### Typing
41
- - Strict typing everywhere: function signatures, variables, collections.
42
- - No implicit `any` or untyped parameters in typed languages.
43
-
44
- ### No flag parameters
45
- - Never write a function with a boolean/enum parameter that switches behavior.
46
- Write separate named functions instead.
47
-
48
- ### Dead code
49
- - Delete dead code. Do not comment it out.
50
- Commented-out code belongs in git history, not in files.
51
- - Check if logic already exists before writing new code: `rg` to search first.
52
-
53
- ---
54
-
55
- ## Conventions — WARN on violation
56
-
57
- ### Code structure
58
- - Functions do one thing. If you are writing "and" in a function description,
59
- split it into two functions.
60
- - Prefer functional programming in greenfield code; classes only for connectors/interfaces.
61
- Follow existing project conventions in established codebases.
62
- - All imports at the top of the file.
63
- - Follow DRY, KISS, YAGNI.
64
-
65
- ### Naming
66
- - Variable names describe what they contain: `subscriptionIds` not `ids`,
67
- `retryDelayMs` not `delay`.
68
- - Functions: verb-noun format. Name signals intent and side effects.
69
-
70
- ### Testing
71
- - Write tests for ALL new code in production paths.
72
- - Spike/prototype carve-out: skip tests only if explicitly marked spike/prototype.
73
- Flag test debt in `status.md` under `## Test Debt`.
74
- - Run tests before marking any task complete.
75
- - Mock external dependencies only — never mock the code under test.
76
- - Test edge cases and error paths, not just happy paths.
77
- - If existing tests break: fix them. Do not claim they are unrelated.
78
- - Never say "this should work" — demonstrate it with output, log line, or test result.
79
-
80
- ### Dependency management
81
- Before adding any new package:
82
- 1. Search first — check if functionality exists in codebase or stdlib (`rg`).
83
- 2. Evaluate: maintenance status, last publish, open issues, bus factor.
84
- 3. Minimize surface area — implement yourself if you only need one function.
85
- 4. Pin versions — exact versions in lockfiles. No floating ranges in production deps.
86
- 5. New production dependency requires explicit approval.
87
-
88
- ### Documentation
89
- - Comments explain WHY, not WHAT. If the comment describes what the code does,
90
- rewrite the code to be self-describing instead.
91
- - Update docs and comments when changing logic. Stale comments actively mislead.
92
- - Code is primary documentation — clear naming, types, docstrings.
93
- - YAML frontmatter on all markdown files:
94
- ```yaml
95
- ---
96
- created: YYYY-MM-DD
97
- status: draft|active|completed
98
- tags: [relevant, tags]
99
- source: agent
100
- ---
101
- ```
102
-
103
- ### Scripts
104
- - Scripts that modify resources must have a dry-run or preview step before live run.
105
-
106
16
  ### Tool preferences
107
17
  - Use Read/Edit/Write tools instead of cat/sed/echo.
108
18
  - Use `rg` (ripgrep) for searching code, not grep.
109
19
  - Use `git --no-pager` for all git commands.
110
20
  - Use subagents for context-heavy research and code review.
111
21
  - Non-interactive commands only — no interactive prompts.
112
- - Prefer MCP tools for current documentation (context7, Playwright).
22
+ - Prefer MCP tools for current documentation (context7).
23
+ - YAML frontmatter on all markdown files.
113
24
 
114
25
  ---
115
26
 
116
- ## Linter Delegation
27
+ ## Quality Architecture
117
28
 
118
- Style, formatting, import ordering, complexity thresholds, and security patterns
119
- are enforced by automated tooling (golangci-lint, shellcheck, hadolint, tflint,
120
- semgrep). Rules files cover ONLY:
121
- - Architecture decisions tooling cannot express
122
- - Permission boundaries and file-group scoping
123
- - Error learning from real session failures
124
- - Verification command references
29
+ Code quality is enforced proactively, not reactively:
30
+ - **Layer 1 (Principles)**: `code-excellence.md`, `engineering-judgment.md` shape reasoning
31
+ - **Layer 2 (Constraints)**: `code-quality.md` hard limits during generation
32
+ - **Layer 3 (Verification)**: `/px-self-verify` — prove correctness before commit
33
+ - **Safety net**: DeepSource (cloud) — comprehensive analysis on push
125
34
 
126
- Do NOT duplicate in CLAUDE.md what hooks already enforce.
35
+ Detailed rules: error handling, naming, testing, dependencies, simplicity, and
36
+ judgment live in those files. This file covers only what they do not:
37
+ Context7 mandate, tool preferences, and verification commands.
127
38
 
128
39
  ---
129
40
 
130
41
  ## Verification Commands
131
42
 
132
- Single-file (matches PostToolUse hooks):
43
+ Single-file:
133
44
  - `go vet <file>` / `shellcheck <file>` / `hadolint Dockerfile` / `markdownlint <file>.md`
134
45
 
135
- Project-level (matches pre-commit + /verify):
136
- - `golangci-lint run`
137
- - `semgrep --config=auto --error .`
46
+ Project-level:
47
+ - `deepsource issues --path <file>` — query DeepSource findings
48
+ - `deepsource repo status` — repo analysis status
138
49
  - `govulncheck ./...`
139
50
  - `trivy config .`
140
51
 
@@ -147,12 +58,6 @@ git diff --staged | grep -iE "(password|secret|token|key)\s*=\s*['\"][^'\"$]"
147
58
 
148
59
  # Find TODO/FIXME left in staged files
149
60
  git diff --staged | grep -E "(TODO|FIXME|HACK|XXX)"
150
-
151
- # Find commented-out code blocks (language-agnostic)
152
- git diff --staged | grep -E "^\+\s*(#|//|--|\*)\s*(def |function |class |var |const |let )"
153
-
154
- # Check for untyped any in TypeScript staged files
155
- git diff --staged -- '*.ts' | grep -E ": any"
156
61
  ```
157
62
 
158
63
  ---