@esoteric-logic/praxis-harness 2.5.1 → 2.6.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 (39) hide show
  1. package/base/CLAUDE.md +17 -1
  2. package/base/configs/mcp-servers.json +26 -0
  3. package/base/configs/registry.json +113 -0
  4. package/base/hooks/credential-guard.sh +98 -0
  5. package/base/hooks/dep-audit.sh +105 -0
  6. package/base/hooks/quality-check.sh +4 -3
  7. package/base/hooks/recursion-guard.sh +76 -0
  8. package/base/hooks/session-data-collect.sh +3 -0
  9. package/base/hooks/settings-hooks.json +18 -0
  10. package/base/rules/coding.md +2 -2
  11. package/base/rules/dependency-freshness.md +50 -0
  12. package/base/rules/live-docs-required.md +81 -0
  13. package/base/rules/security-posture.md +62 -0
  14. package/base/skills/blind-judge/SKILL.md +88 -0
  15. package/base/skills/context7-lookup/SKILL.md +17 -6
  16. package/base/skills/deliberate/SKILL.md +103 -0
  17. package/base/skills/dep-hygiene/SKILL.md +93 -0
  18. package/base/skills/pre-commit-lint/SKILL.md +2 -3
  19. package/base/skills/research/SKILL.md +106 -0
  20. package/base/skills/scaffold-new/SKILL.md +1 -4
  21. package/base/skills/scaffold-new/references/repo-CLAUDE-md-template.md +1 -1
  22. package/bin/praxis-preflight.sh +317 -0
  23. package/package.json +1 -1
  24. package/scripts/install-tools.sh +3 -23
  25. package/scripts/lint-harness.sh +1 -1
  26. package/scripts/test-harness.sh +1 -26
  27. package/base/configs/vale/.vale.ini +0 -17
  28. package/base/configs/vale/Praxis/AISlop.yml +0 -90
  29. package/base/configs/vale/Praxis/CopulaAvoidance.yml +0 -22
  30. package/base/configs/vale/Praxis/ElegantVariation.yml +0 -14
  31. package/base/configs/vale/Praxis/HeadingCase.yml +0 -26
  32. package/base/configs/vale/Praxis/Hedging.yml +0 -22
  33. package/base/configs/vale/Praxis/NaturalVoice.yml +0 -85
  34. package/base/configs/vale/Praxis/Precision.yml +0 -60
  35. package/base/configs/vale/Praxis/SentenceLength.yml +0 -6
  36. package/base/configs/vale/Praxis/Terminology.yml +0 -25
  37. package/base/configs/vale/Praxis/vocabularies/accept.txt +0 -32
  38. package/base/configs/vale/Praxis/vocabularies/reject.txt +0 -3
  39. package/base/skills/prose-review/SKILL.md +0 -165
@@ -0,0 +1,317 @@
1
+ #!/usr/bin/env bash
2
+ # praxis-preflight.sh — "Ready to build" gate
3
+ # Phase 1 is hard-blocking (exit 1). Phases 2-5 produce warnings only.
4
+ # Also implements: set-key subcommand for secret management.
5
+ set -euo pipefail
6
+
7
+ # ─── Colors ───
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[0;33m'
11
+ CYAN='\033[0;36m'
12
+ BOLD='\033[1m'
13
+ NC='\033[0m'
14
+
15
+ PASS=0
16
+ WARN=0
17
+ BLOCK=0
18
+ PRAXIS_DIR="$HOME/.praxis"
19
+ SECRETS_FILE="$PRAXIS_DIR/secrets"
20
+ REPORT_FILE="$PRAXIS_DIR/preflight-report.json"
21
+
22
+ ok() { echo -e " ${GREEN}✓${NC} $1"; PASS=$((PASS + 1)); }
23
+ warn() { echo -e " ${YELLOW}⚠${NC} $1"; WARN=$((WARN + 1)); }
24
+ fail() { echo -e " ${RED}✗${NC} $1"; BLOCK=$((BLOCK + 1)); }
25
+ step() { echo -e "\n${CYAN}${BOLD}$1${NC}"; }
26
+
27
+ # ═══════════════════════════════════════════
28
+ # Subcommand: set-key
29
+ # ═══════════════════════════════════════════
30
+ if [[ "${1:-}" == "set-key" ]]; then
31
+ KEY="${2:-}"
32
+ VALUE="${3:-}"
33
+ if [[ -z "$KEY" || -z "$VALUE" ]]; then
34
+ echo "Usage: praxis-preflight.sh set-key KEY VALUE"
35
+ echo "Example: praxis-preflight.sh set-key PERPLEXITY_API_KEY pplx-..."
36
+ exit 1
37
+ fi
38
+
39
+ # Create secure directory
40
+ mkdir -p "$PRAXIS_DIR"
41
+ chmod 700 "$PRAXIS_DIR"
42
+
43
+ # Create or update secrets file
44
+ if [[ -f "$SECRETS_FILE" ]]; then
45
+ # Remove existing key line
46
+ grep -v "^${KEY}=" "$SECRETS_FILE" > "${SECRETS_FILE}.tmp" 2>/dev/null || true
47
+ mv "${SECRETS_FILE}.tmp" "$SECRETS_FILE"
48
+ fi
49
+
50
+ echo "${KEY}=${VALUE}" >> "$SECRETS_FILE"
51
+ chmod 600 "$SECRETS_FILE"
52
+
53
+ MASKED="${VALUE:0:8}********"
54
+ echo -e "${GREEN}✓${NC} Stored $KEY (${MASKED})"
55
+ exit 0
56
+ fi
57
+
58
+ # ═══════════════════════════════════════════
59
+ # Load secrets from file if it exists
60
+ # ═══════════════════════════════════════════
61
+ load_secrets() {
62
+ if [[ -f "$SECRETS_FILE" ]]; then
63
+ while IFS='=' read -r key value; do
64
+ [[ -z "$key" || "$key" == \#* ]] && continue
65
+ export "$key=$value" 2>/dev/null || true
66
+ done < "$SECRETS_FILE"
67
+ fi
68
+ }
69
+
70
+ # ═══════════════════════════════════════════
71
+ # Version comparison helper
72
+ # ═══════════════════════════════════════════
73
+ version_gte() {
74
+ # Returns 0 if $1 >= $2
75
+ printf '%s\n%s' "$2" "$1" | sort -V -C 2>/dev/null
76
+ }
77
+
78
+ echo ""
79
+ echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}"
80
+ echo -e "${BOLD}║ Praxis Preflight Check ║${NC}"
81
+ echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}"
82
+
83
+ load_secrets
84
+
85
+ # ═══════════════════════════════════════════
86
+ # Phase 1: BLOCKING — hard exit if any fail
87
+ # ═══════════════════════════════════════════
88
+ step "Phase 1: Required (blocking)"
89
+
90
+ # Claude auth
91
+ if claude auth status &>/dev/null 2>&1; then
92
+ ok "Claude Code authenticated"
93
+ else
94
+ fail "Claude Code not authenticated"
95
+ echo -e " Fix: ${CYAN}claude auth login${NC}"
96
+ fi
97
+
98
+ # Node.js >= 18
99
+ if command -v node &>/dev/null; then
100
+ NODE_VER=$(node --version 2>/dev/null | sed 's/^v//')
101
+ if version_gte "$NODE_VER" "18.0.0"; then
102
+ ok "Node.js $NODE_VER (>= 18 required)"
103
+ else
104
+ fail "Node.js $NODE_VER is below minimum 18.0.0"
105
+ echo -e " Fix: ${CYAN}brew install node${NC}"
106
+ fi
107
+ else
108
+ fail "Node.js not found"
109
+ echo -e " Fix: ${CYAN}brew install node${NC}"
110
+ fi
111
+
112
+ # jq
113
+ if command -v jq &>/dev/null; then
114
+ ok "jq $(jq --version 2>/dev/null | sed 's/^jq-//' || echo 'installed')"
115
+ else
116
+ fail "jq not found"
117
+ echo -e " Fix: ${CYAN}brew install jq${NC}"
118
+ fi
119
+
120
+ # git config
121
+ GIT_NAME=$(git config --global user.name 2>/dev/null || true)
122
+ GIT_EMAIL=$(git config --global user.email 2>/dev/null || true)
123
+ if [[ -n "$GIT_NAME" && -n "$GIT_EMAIL" ]]; then
124
+ ok "Git identity: $GIT_NAME <$GIT_EMAIL>"
125
+ else
126
+ if [[ -z "$GIT_NAME" ]]; then
127
+ fail "git config user.name not set"
128
+ echo -e " Fix: ${CYAN}git config --global user.name \"Your Name\"${NC}"
129
+ fi
130
+ if [[ -z "$GIT_EMAIL" ]]; then
131
+ fail "git config user.email not set"
132
+ echo -e " Fix: ${CYAN}git config --global user.email \"you@example.com\"${NC}"
133
+ fi
134
+ fi
135
+
136
+ # Check if Phase 1 failed
137
+ if [[ $BLOCK -gt 0 ]]; then
138
+ echo ""
139
+ echo -e " ${RED}${BOLD}PREFLIGHT FAILED${NC} — fix $BLOCK blocking issue(s) above"
140
+ # Write report even on failure
141
+ mkdir -p "$PRAXIS_DIR" 2>/dev/null || true
142
+ jq -nc \
143
+ --argjson pass "$PASS" \
144
+ --argjson warn "$WARN" \
145
+ --argjson block "$BLOCK" \
146
+ --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
147
+ --arg status "failed" \
148
+ '{timestamp: $ts, status: $status, pass: $pass, warn: $warn, block: $block}' \
149
+ > "$REPORT_FILE" 2>/dev/null || true
150
+ exit 1
151
+ fi
152
+
153
+ # ═══════════════════════════════════════════
154
+ # Phase 2: GitHub Auth
155
+ # ═══════════════════════════════════════════
156
+ step "Phase 2: GitHub authentication"
157
+
158
+ if gh auth status &>/dev/null 2>&1; then
159
+ ok "GitHub CLI authenticated"
160
+ # Auto-populate GITHUB_TOKEN
161
+ GH_TOKEN=$(gh auth token 2>/dev/null || true)
162
+ if [[ -n "$GH_TOKEN" ]]; then
163
+ mkdir -p "$PRAXIS_DIR"
164
+ chmod 700 "$PRAXIS_DIR"
165
+ if [[ -f "$SECRETS_FILE" ]]; then
166
+ grep -v "^GITHUB_TOKEN=" "$SECRETS_FILE" > "${SECRETS_FILE}.tmp" 2>/dev/null || true
167
+ mv "${SECRETS_FILE}.tmp" "$SECRETS_FILE"
168
+ fi
169
+ echo "GITHUB_TOKEN=${GH_TOKEN}" >> "$SECRETS_FILE"
170
+ chmod 600 "$SECRETS_FILE"
171
+ ok "GITHUB_TOKEN auto-populated from gh auth"
172
+ export GITHUB_TOKEN="$GH_TOKEN"
173
+ fi
174
+ elif [[ -n "${GITHUB_TOKEN:-}" ]]; then
175
+ ok "GITHUB_TOKEN found in environment"
176
+ else
177
+ warn "GitHub not authenticated — github-mcp feature disabled"
178
+ echo -e " Fix: ${CYAN}gh auth login${NC}"
179
+ fi
180
+
181
+ # ═══════════════════════════════════════════
182
+ # Phase 3: Optional keys
183
+ # ═══════════════════════════════════════════
184
+ step "Phase 3: Optional API keys"
185
+
186
+ # PERPLEXITY_API_KEY
187
+ if [[ -n "${PERPLEXITY_API_KEY:-}" ]]; then
188
+ if [[ "$PERPLEXITY_API_KEY" == pplx-* ]]; then
189
+ MASKED="${PERPLEXITY_API_KEY:0:8}********"
190
+ ok "PERPLEXITY_API_KEY ($MASKED) — live-research enabled"
191
+ else
192
+ warn "PERPLEXITY_API_KEY set but doesn't start with pplx-"
193
+ fi
194
+ else
195
+ warn "PERPLEXITY_API_KEY not set — live research via Sonar disabled"
196
+ echo -e " Get key: ${CYAN}https://www.perplexity.ai/settings/api${NC}"
197
+ echo -e " Set: ${CYAN}praxis-preflight.sh set-key PERPLEXITY_API_KEY pplx-...${NC}"
198
+ fi
199
+
200
+ # OBSIDIAN_VAULT
201
+ VAULT_PATH="${OBSIDIAN_VAULT:-}"
202
+ if [[ -z "$VAULT_PATH" ]]; then
203
+ # Try to read from praxis.config.json
204
+ CONFIG_FILE="$HOME/.claude/praxis.config.json"
205
+ if [[ -f "$CONFIG_FILE" ]]; then
206
+ VAULT_PATH=$(jq -r '.vault_path // empty' "$CONFIG_FILE" 2>/dev/null || true)
207
+ fi
208
+ fi
209
+
210
+ if [[ -n "$VAULT_PATH" && -d "$VAULT_PATH" ]]; then
211
+ ok "Vault: $VAULT_PATH"
212
+ else
213
+ warn "No Obsidian vault configured — long-term memory disabled"
214
+ echo -e " Set: ${CYAN}praxis-preflight.sh set-key OBSIDIAN_VAULT /path/to/vault${NC}"
215
+ fi
216
+
217
+ # ═══════════════════════════════════════════
218
+ # Phase 4: MCP servers
219
+ # ═══════════════════════════════════════════
220
+ step "Phase 4: MCP servers"
221
+
222
+ if command -v claude &>/dev/null; then
223
+ MCP_LIST=$(claude mcp list 2>/dev/null || true)
224
+
225
+ # Context7 (always expected)
226
+ if echo "$MCP_LIST" | grep -q "context7"; then
227
+ ok "context7 MCP registered (live docs)"
228
+ else
229
+ warn "context7 MCP not registered"
230
+ echo -e " Fix: ${CYAN}bash scripts/onboard-mcp.sh context7${NC}"
231
+ fi
232
+
233
+ # GitHub MCP (if token available)
234
+ if [[ -n "${GITHUB_TOKEN:-}" ]]; then
235
+ if echo "$MCP_LIST" | grep -q "github"; then
236
+ ok "github MCP registered"
237
+ else
238
+ warn "github MCP not registered (token available)"
239
+ echo -e " Fix: ${CYAN}bash scripts/onboard-mcp.sh github${NC}"
240
+ fi
241
+ fi
242
+
243
+ # Perplexity MCP (if key available)
244
+ if [[ -n "${PERPLEXITY_API_KEY:-}" ]]; then
245
+ if echo "$MCP_LIST" | grep -qi "perplexity"; then
246
+ ok "perplexity MCP registered (live research)"
247
+ else
248
+ warn "perplexity MCP not registered (key available)"
249
+ echo -e " Fix: ${CYAN}bash scripts/onboard-mcp.sh perplexity${NC}"
250
+ fi
251
+ fi
252
+ else
253
+ warn "claude CLI not available — cannot check MCP servers"
254
+ fi
255
+
256
+ # ═══════════════════════════════════════════
257
+ # Phase 5: Optional tools + hooks
258
+ # ═══════════════════════════════════════════
259
+ step "Phase 5: Optional tools & hooks"
260
+
261
+ # Optional security tools
262
+ for tool in trufflehog gitleaks osv-scanner; do
263
+ if command -v "$tool" &>/dev/null; then
264
+ ok "$tool available"
265
+ else
266
+ warn "$tool not installed — enhanced scanning unavailable"
267
+ fi
268
+ done
269
+
270
+ # Check hook scripts exist and are executable
271
+ HOOKS_DIR="$HOME/.claude/hooks"
272
+ REQUIRED_HOOKS=(secret-scan.sh file-guard.sh identity-check.sh credential-guard.sh quality-check.sh session-data-collect.sh)
273
+ for hook in "${REQUIRED_HOOKS[@]}"; do
274
+ if [[ -x "$HOOKS_DIR/$hook" ]] || [[ -L "$HOOKS_DIR/$hook" ]]; then
275
+ ok "Hook: $hook"
276
+ else
277
+ warn "Hook missing or not executable: $hook"
278
+ fi
279
+ done
280
+
281
+ # ═══════════════════════════════════════════
282
+ # Summary
283
+ # ═══════════════════════════════════════════
284
+ echo ""
285
+ echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
286
+ echo -e " Pass: ${GREEN}${BOLD}$PASS${NC}"
287
+ echo -e " Warnings: ${YELLOW}${BOLD}$WARN${NC}"
288
+ echo -e " Blocking: ${RED}${BOLD}$BLOCK${NC}"
289
+
290
+ if [[ $BLOCK -eq 0 ]]; then
291
+ echo -e " ${GREEN}${BOLD}✓ Praxis ready to build${NC}"
292
+ else
293
+ echo -e " ${RED}${BOLD}PREFLIGHT FAILED — fix blocking issues above${NC}"
294
+ fi
295
+ echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
296
+
297
+ # Write JSON report
298
+ mkdir -p "$PRAXIS_DIR" 2>/dev/null || true
299
+ chmod 700 "$PRAXIS_DIR" 2>/dev/null || true
300
+
301
+ STATUS="passed"
302
+ [[ $BLOCK -gt 0 ]] && STATUS="failed"
303
+ [[ $WARN -gt 0 && $BLOCK -eq 0 ]] && STATUS="passed_with_warnings"
304
+
305
+ if command -v jq &>/dev/null; then
306
+ jq -nc \
307
+ --argjson pass "$PASS" \
308
+ --argjson warn "$WARN" \
309
+ --argjson block "$BLOCK" \
310
+ --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
311
+ --arg status "$STATUS" \
312
+ '{timestamp: $ts, status: $status, pass: $pass, warn: $warn, block: $block}' \
313
+ > "$REPORT_FILE" 2>/dev/null || true
314
+ fi
315
+
316
+ [[ $BLOCK -gt 0 ]] && exit 1
317
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esoteric-logic/praxis-harness",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Layered Claude Code harness — workflow discipline, AI-Kits, persistent vault integration",
5
5
  "bin": {
6
6
  "praxis-harness": "./bin/praxis.js"
@@ -44,12 +44,12 @@ install_go() { go install "$@" 2>/dev/null || true; }
44
44
  # ── Core (always) ──
45
45
  echo "── Installing core tools ──"
46
46
  if [ "$PKG" = "brew" ]; then
47
- install_brew shellcheck shfmt jq vale gitleaks
47
+ install_brew shellcheck shfmt jq gitleaks
48
48
  else
49
49
  sudo apt-get update -qq
50
50
  sudo apt-get install -y -qq shellcheck jq
51
51
  install_go mvdan.cc/sh/v3/cmd/shfmt@latest
52
- echo "NOTE: Install vale and gitleaks manually (see https://vale.sh/docs/install)"
52
+ echo "NOTE: Install gitleaks manually (see https://github.com/gitleaks/gitleaks)"
53
53
  fi
54
54
  install_npm markdownlint-cli @commitlint/cli @commitlint/config-conventional
55
55
  install_pip semgrep yamllint
@@ -87,31 +87,11 @@ if command -v docker &>/dev/null; then
87
87
  fi
88
88
  fi
89
89
 
90
- # ── Vale setup (sync packages + copy Praxis rules) ──
91
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
92
- VALE_CONFIG_DIR="$SCRIPT_DIR/../base/configs/vale"
93
- if command -v vale &>/dev/null && [ -f "$VALE_CONFIG_DIR/.vale.ini" ]; then
94
- echo ""
95
- echo "── Setting up Vale prose linter ──"
96
- (cd "$VALE_CONFIG_DIR" && vale sync 2>/dev/null || true)
97
- if [ -d "$VALE_CONFIG_DIR/Praxis" ] && [ -d "$VALE_CONFIG_DIR/.vale-styles" ]; then
98
- cp -R "$VALE_CONFIG_DIR/Praxis" "$VALE_CONFIG_DIR/.vale-styles/Praxis"
99
- echo " Praxis rules copied to .vale-styles/"
100
- # Copy vocabulary files to Vale's expected location
101
- if [ -d "$VALE_CONFIG_DIR/Praxis/vocabularies" ]; then
102
- mkdir -p "$VALE_CONFIG_DIR/.vale-styles/config/vocabularies/Praxis"
103
- cp "$VALE_CONFIG_DIR/Praxis/vocabularies/"*.txt "$VALE_CONFIG_DIR/.vale-styles/config/vocabularies/Praxis/"
104
- echo " Praxis vocabulary copied to .vale-styles/config/vocabularies/"
105
- fi
106
- fi
107
- fi
108
-
109
90
  # ── VS Code extensions ──
110
91
  if command -v code &>/dev/null; then
111
92
  echo ""
112
93
  echo "── Installing VS Code extensions ──"
113
94
  CORE_EXTENSIONS=(
114
- chrischinchilla.vale-vscode
115
95
  timonwong.shellcheck
116
96
  editorconfig.editorconfig
117
97
  davidanson.vscode-markdownlint
@@ -134,7 +114,7 @@ echo ""
134
114
  echo "=== Done. Run 'bash scripts/install-tools.sh --all' to install all stacks. ==="
135
115
  echo ""
136
116
  echo "Installed tools:"
137
- for tool in shellcheck shfmt jq vale gitleaks goimports golangci-lint govulncheck tflint trivy infracost hadolint semgrep yamllint markdownlint commitlint; do
117
+ for tool in shellcheck shfmt jq gitleaks goimports golangci-lint govulncheck tflint trivy infracost hadolint semgrep yamllint markdownlint commitlint; do
138
118
  if command -v "$tool" &>/dev/null; then
139
119
  printf " ✓ %s\n" "$tool"
140
120
  else
@@ -124,7 +124,7 @@ while IFS= read -r file; do
124
124
  | grep -vE '`[^`]*\{[^}]+\}[^`]*`' \
125
125
  | grep -vE '^[0-9]+:\s*#' \
126
126
  | grep -vE '^[0-9]+:\s*echo ' \
127
- | grep -vE '\{vault_path\}|\{today_date\}|\{project-slug\}|\{YYYY-MM-DD\}|\{kebab-title\}|\{date\}|\{[nN]\}|\{1-line\}|\{ISO timestamp\}|\{repo_root\}|\{identity_email\}|\{stack\}|\{placeholder\}|\{placeholders\}|\{http_code\}' \
127
+ | grep -vE '\{vault_path\}|\{today_date\}|\{project-slug\}|\{YYYY-MM-DD\}|\{kebab-title\}|\{date\}|\{[nN]\}|\{1-line\}|\{ISO timestamp\}|\{repo_root\}|\{identity_email\}|\{stack\}|\{placeholder\}|\{placeholders\}|\{http_code\}|\$\{[A-Z_]+\}|\$[a-z_]+' \
128
128
  || true)
129
129
  if [[ -n "$matches" ]]; then
130
130
  rel_path="${file#"$REPO_PATH"/}"
@@ -204,38 +204,13 @@ echo "Config directory:"
204
204
 
205
205
  if [[ -d "$REPO_PATH/base/configs" ]]; then
206
206
  ok "base/configs/ exists"
207
- for config_dir in vale linters; do
207
+ for config_dir in linters; do
208
208
  if [[ -d "$REPO_PATH/base/configs/$config_dir" ]]; then
209
209
  ok "base/configs/$config_dir/ exists"
210
210
  else
211
211
  error "base/configs/$config_dir/ missing"
212
212
  fi
213
213
  done
214
-
215
- # Vale config check
216
- if [[ -f "$REPO_PATH/base/configs/vale/.vale.ini" ]]; then
217
- ok "vale config exists"
218
- else
219
- error "vale config missing"
220
- fi
221
-
222
- # Vale rule files
223
- VALE_COUNT=$(find "$REPO_PATH/base/configs/vale/Praxis" -name "*.yml" 2>/dev/null | wc -l | tr -d ' ')
224
- if [[ "$VALE_COUNT" -ge 6 ]]; then
225
- ok "vale Praxis rules: $VALE_COUNT files"
226
- else
227
- error "vale Praxis rules: expected >=6, found $VALE_COUNT"
228
- fi
229
-
230
- # YAML validation on vale rules
231
- for f in "$REPO_PATH"/base/configs/vale/Praxis/*.yml; do
232
- name=$(basename "$f")
233
- if python3 -c "import yaml; yaml.safe_load(open('$f'))" 2>/dev/null; then
234
- ok "vale/$name valid YAML"
235
- else
236
- error "vale/$name invalid YAML"
237
- fi
238
- done
239
214
  else
240
215
  error "base/configs/ directory missing"
241
216
  fi
@@ -1,17 +0,0 @@
1
- StylesPath = .vale-styles
2
- MinAlertLevel = suggestion
3
- Vocab = Praxis
4
-
5
- Packages = Google, proselint, alex, write-good, Readability
6
-
7
- # Full suite on Markdown
8
- [*.md]
9
- BasedOnStyles = Praxis, Google, proselint, alex, write-good, Readability
10
-
11
- # Comment-only scanning on code files
12
- [*.{go,tf,sh,ps1}]
13
- BasedOnStyles = Praxis
14
-
15
- # Praxis rules only on YAML
16
- [*.{yml,yaml}]
17
- BasedOnStyles = Praxis
@@ -1,90 +0,0 @@
1
- extends: substitution
2
- message: "AI vocabulary detected: '%s' — rephrase in plain language."
3
- level: warning
4
- ignorecase: true
5
- swap:
6
- delve: "examine, explore, investigate"
7
- tapestry: "combination, mix"
8
- multifaceted: "complex, varied"
9
- leverage: "use"
10
- paradigm: "model, approach"
11
- synergy: "collaboration, combination"
12
- holistic: "complete, whole"
13
- robust: "strong, reliable"
14
- seamless: "smooth"
15
- cutting-edge: "modern, latest"
16
- game-changer: "improvement, breakthrough"
17
- deep dive: "detailed look, analysis"
18
- unpack: "explain, examine"
19
- landscape: "field, area, environment"
20
- ecosystem: "system, environment"
21
- streamline: "simplify"
22
- spearhead: "lead"
23
- groundbreaking: "new, innovative"
24
- transformative: "significant"
25
- empower: "enable, help"
26
- reimagine: "rethink, redesign"
27
- cornerstone: "foundation, basis"
28
- pivotal: "important, key"
29
- catalyst: "trigger, cause"
30
- navigate: "manage, handle"
31
- harness: "use"
32
- unlock: "enable, reveal"
33
- bolster: "strengthen, support"
34
- underscore: "highlight, emphasize"
35
- illuminate: "explain, clarify"
36
- forge: "build, create"
37
- foster: "encourage, develop"
38
- cultivate: "develop, build"
39
- paramount: "important, critical"
40
- meticulous: "careful, thorough"
41
- intricate: "complex, detailed"
42
- nuanced: "subtle"
43
- comprehensive: "complete, thorough"
44
- invaluable: "very useful, essential"
45
- instrumental: "important, helpful"
46
- embark: "start, begin"
47
- endeavor: "effort, attempt"
48
- realm: "area, field"
49
- facet: "aspect, part"
50
- Moreover: "Also, Additionally"
51
- Furthermore: "Also"
52
- Notably: "Note that"
53
- Importantly: "Note"
54
- Essentially: "(omit or rewrite)"
55
- Fundamentally: "(omit or rewrite)"
56
- Undoubtedly: "(omit or rewrite)"
57
- Interestingly: "(omit or rewrite)"
58
- testament: "proof, evidence"
59
- beacon: "example, guide"
60
- resonate: "connect, appeal"
61
- bespoke: "custom"
62
- elevate: "improve, raise"
63
- amplify: "increase, strengthen"
64
- augment: "add to, supplement"
65
- myriad: "many"
66
- plethora: "many, excess"
67
- burgeoning: "growing"
68
- nascent: "new, early"
69
- advent: "arrival, start"
70
- proliferation: "spread, growth"
71
- propel: "drive, push"
72
- overarching: "main, overall"
73
- dovetail: "fit, align"
74
- tailored: "custom, specific"
75
- juxtapose: "compare, contrast"
76
- dichotomy: "contrast, split"
77
- eponymous: "named after"
78
- erstwhile: "former"
79
- zeitgeist: "spirit of the time"
80
- ethos: "values, character"
81
- nexus: "connection, link"
82
- crucible: "test, trial"
83
- vanguard: "forefront, leading edge"
84
- linchpin: "key element"
85
- bedrock: "foundation"
86
- scaffolding: "framework, structure"
87
- underpinning: "basis, foundation"
88
- bulwark: "defense, safeguard"
89
- bastion: "stronghold"
90
- harbinger: "sign, indicator"
@@ -1,22 +0,0 @@
1
- extends: existence
2
- message: "Inflated copula: '%s' — simplify."
3
- level: suggestion
4
- ignorecase: true
5
- tokens:
6
- - "serves as a"
7
- - "acts as a"
8
- - "functions as a"
9
- - "plays a pivotal role"
10
- - "plays a crucial role"
11
- - "plays a vital role"
12
- - "plays a key role"
13
- - "plays an important role"
14
- - "boasts a"
15
- - "represents a"
16
- - "constitutes a"
17
- - "comprises a"
18
- - "stands as a"
19
- - "remains a"
20
- - "proves to be"
21
- - "turns out to be"
22
- - "happens to be"
@@ -1,14 +0,0 @@
1
- extends: existence
2
- message: "Elegant variation: '%s' — use the plain term."
3
- level: suggestion
4
- ignorecase: true
5
- tokens:
6
- - "the aforementioned"
7
- - "the above-mentioned"
8
- - "the previously mentioned"
9
- - "this individual"
10
- - "said individual"
11
- - "the eponymous"
12
- - "this entity"
13
- - "the latter"
14
- - "the former"
@@ -1,26 +0,0 @@
1
- extends: capitalization
2
- message: "'%s' should use sentence case."
3
- level: warning
4
- scope: heading
5
- match: $sentence
6
- indicators:
7
- - ":"
8
- exceptions:
9
- - Praxis
10
- - CLAUDE
11
- - MCP
12
- - SPEC
13
- - ADR
14
- - API
15
- - CLI
16
- - VS Code
17
- - GitHub
18
- - Azure
19
- - Terraform
20
- - Obsidian
21
- - Node.js
22
- - TypeScript
23
- - JavaScript
24
- - PowerShell
25
- - YAML
26
- - JSON
@@ -1,22 +0,0 @@
1
- extends: existence
2
- message: "Hedging detected: '%s' — commit to a position or remove."
3
- level: suggestion
4
- ignorecase: true
5
- tokens:
6
- - "it could potentially"
7
- - "it might potentially"
8
- - "it may potentially"
9
- - "arguably"
10
- - "it remains to be seen"
11
- - "only time will tell"
12
- - "it is not unreasonable to"
13
- - "one could argue"
14
- - "some might say"
15
- - "it would not be wrong to"
16
- - "to some extent"
17
- - "to a certain degree"
18
- - "in some ways"
19
- - "more or less"
20
- - "for the most part"
21
- - "by and large"
22
- - "generally speaking"