qualia-framework-v2 2.0.0 → 2.1.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.
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ # Catch dangerous SQL patterns in migration files
3
+ # Runs as PreToolUse hook on Write/Edit of migration files
4
+
5
+ INPUT=$(cat)
6
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
7
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // ""' 2>/dev/null)
8
+
9
+ # Only check migration/SQL files
10
+ case "$FILE" in
11
+ *migration*|*migrate*|*.sql) ;;
12
+ *) exit 0 ;;
13
+ esac
14
+
15
+ ERRORS=""
16
+
17
+ # DROP TABLE without safeguards
18
+ if echo "$CONTENT" | grep -qi "DROP TABLE" && ! echo "$CONTENT" | grep -qi "IF EXISTS"; then
19
+ ERRORS="${ERRORS}\n ✗ DROP TABLE without IF EXISTS"
20
+ fi
21
+
22
+ # DELETE without WHERE
23
+ if echo "$CONTENT" | grep -qi "DELETE FROM" && ! echo "$CONTENT" | grep -qi "WHERE"; then
24
+ ERRORS="${ERRORS}\n ✗ DELETE FROM without WHERE clause"
25
+ fi
26
+
27
+ # TRUNCATE (almost always wrong in migrations)
28
+ if echo "$CONTENT" | grep -qi "TRUNCATE"; then
29
+ ERRORS="${ERRORS}\n ✗ TRUNCATE detected — are you sure?"
30
+ fi
31
+
32
+ # CREATE TABLE without RLS
33
+ if echo "$CONTENT" | grep -qi "CREATE TABLE" && ! echo "$CONTENT" | grep -qi "ENABLE ROW LEVEL SECURITY"; then
34
+ ERRORS="${ERRORS}\n ✗ CREATE TABLE without ENABLE ROW LEVEL SECURITY"
35
+ fi
36
+
37
+ if [ -n "$ERRORS" ]; then
38
+ echo "◆ Migration guard — dangerous patterns found:"
39
+ echo -e "$ERRORS"
40
+ echo ""
41
+ echo "Fix these before proceeding. If intentional, ask Fawzi to approve."
42
+ exit 2
43
+ fi
@@ -12,6 +12,24 @@ if [ -f "tsconfig.json" ]; then
12
12
  echo " ✓ TypeScript"
13
13
  fi
14
14
 
15
+ # Lint check
16
+ if [ -f "package.json" ] && grep -q '"lint"' package.json; then
17
+ if ! npm run lint 2>/dev/null; then
18
+ echo "BLOCKED: Lint errors. Fix before deploying."
19
+ exit 1
20
+ fi
21
+ echo " ✓ Lint"
22
+ fi
23
+
24
+ # Test check
25
+ if [ -f "package.json" ] && grep -q '"test"' package.json; then
26
+ if ! npm test 2>/dev/null; then
27
+ echo "BLOCKED: Tests failed. Fix before deploying."
28
+ exit 1
29
+ fi
30
+ echo " ✓ Tests"
31
+ fi
32
+
15
33
  # Build check
16
34
  if [ -f "package.json" ] && grep -q '"build"' package.json; then
17
35
  if ! npm run build 2>/dev/null; then
package/hooks/pre-push.sh CHANGED
@@ -12,8 +12,12 @@ if [ -f "$STATE" ] && [ -f "$TRACKING" ]; then
12
12
  NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
13
13
 
14
14
  # Update tracking.json with current values
15
- if command -v python3 &>/dev/null; then
16
- python3 -c "
15
+ if ! command -v python3 &>/dev/null; then
16
+ echo "WARNING: python3 not found — tracking.json not updated" >&2
17
+ exit 0
18
+ fi
19
+
20
+ if ! python3 -c "
17
21
  import json
18
22
  with open('$TRACKING', 'r') as f:
19
23
  t = json.load(f)
@@ -23,7 +27,9 @@ t['last_commit'] = '${LAST_COMMIT}'
23
27
  t['last_updated'] = '${NOW}'
24
28
  with open('$TRACKING', 'w') as f:
25
29
  json.dump(t, f, indent=2)
26
- " 2>/dev/null
27
- git add "$TRACKING" 2>/dev/null
30
+ " 2>/tmp/qualia-push-err.txt; then
31
+ echo "WARNING: Failed to update tracking.json — $(cat /tmp/qualia-push-err.txt)" >&2
32
+ exit 0
28
33
  fi
34
+ git add "$TRACKING" 2>/dev/null
29
35
  fi
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "qualia-framework-v2",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
5
5
  "bin": {
6
- "qualia-framework-v2": "./bin/install.js"
6
+ "qualia-framework-v2": "./bin/cli.js"
7
7
  },
8
8
  "keywords": [
9
9
  "claude-code",
@@ -22,6 +22,9 @@
22
22
  "url": "https://github.com/qualia-solutions/qualia-framework-v2"
23
23
  },
24
24
  "homepage": "https://github.com/qualia-solutions/qualia-framework-v2#readme",
25
+ "scripts": {
26
+ "test": "bash tests/hooks.test.sh"
27
+ },
25
28
  "files": [
26
29
  "bin/",
27
30
  "agents/",
@@ -29,10 +32,10 @@
29
32
  "rules/",
30
33
  "skills/",
31
34
  "templates/",
35
+ "tests/",
32
36
  "CLAUDE.md",
33
37
  "guide.md",
34
- "statusline.sh",
35
- "install.sh"
38
+ "statusline.sh"
36
39
  ],
37
40
  "engines": {
38
41
  "node": ">=18"
@@ -22,7 +22,13 @@ echo "---VERIFICATIONS---"
22
22
  ls .planning/phase-*-verification.md 2>/dev/null || echo "NO_VERIFICATIONS"
23
23
  ```
24
24
 
25
- ### 2. Route
25
+ ### Task Routing (size-based)
26
+
27
+ - Single file change, config tweak, typo fix, bug with known cause → `/qualia-quick`
28
+ - One feature, 1-5 files, clear scope, under 2 hours → `/qualia-task`
29
+ - Multi-feature, 5+ files, needs architecture decisions, or part of a roadmap phase → `/qualia-plan`
30
+
31
+ ### 2. Route (state-based)
26
32
 
27
33
  | Condition | Command |
28
34
  |-----------|---------|
@@ -49,7 +49,7 @@ YOUR TASK:
49
49
  {paste the single task block from the plan — title, files, action, context refs, done-when}
50
50
 
51
51
  Execute this task. Read all @file references before writing. Commit when done.
52
- ", subagent_type="general-purpose", description="Task {N}: {title}")
52
+ ", subagent_type="qualia-builder", description="Task {N}: {title}")
53
53
  ```
54
54
 
55
55
  **After each task completes:**
@@ -48,7 +48,7 @@ Phase {N} success criteria: {criteria from STATE.md}
48
48
  {If --gaps: Also read @.planning/phase-{N}-verification.md for failures to fix}
49
49
 
50
50
  Create the plan file at .planning/phase-{N}-plan.md
51
- ", subagent_type="general-purpose", description="Plan phase {N}")
51
+ ", subagent_type="qualia-planner", description="Plan phase {N}")
52
52
  ```
53
53
 
54
54
  ### 3. Review Plan
@@ -82,3 +82,16 @@ Update tracking.json: status → "planned"
82
82
  ```
83
83
  → Run: /qualia-build {N}
84
84
  ```
85
+
86
+ ### Gap Closure Mode (`--gaps`)
87
+
88
+ When invoked as `/qualia-plan {N} --gaps`, the planner is in gap-closure mode:
89
+
90
+ 1. Read `.planning/phase-{N}-verification.md` — extract ONLY the FAIL items
91
+ 2. For each FAIL item, create a targeted fix task:
92
+ - **Files:** The specific files that failed verification
93
+ - **Action:** The specific fix needed (not "fix auth" — "add session persistence check in `src/lib/auth.ts` signIn function")
94
+ - **Done when:** The exact verification criterion that previously failed, restated
95
+ 3. Do NOT re-plan passing items. Do NOT add new features. Gap plans are surgical.
96
+ 4. Write to `.planning/phase-{N}-gaps-plan.md` (separate from original plan)
97
+ 5. All gap tasks are Wave 1 (parallel) unless they share files
@@ -5,7 +5,7 @@ description: "Fast path for small tasks — bug fixes, tweaks, hot fixes. Skips
5
5
 
6
6
  # /qualia-quick — Quick Task
7
7
 
8
- For tasks under 30 minutes that don't need full phase planning. Bug fixes, small features, tweaks.
8
+ For tasks under 1 hour that don't need full phase planning. Single file changes, bug fixes, config tweaks, typo fixes.
9
9
 
10
10
  ## Process
11
11
 
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: qualia-task
3
+ description: "Build a single task — more structured than /qualia-quick, lighter than /qualia-build. Spawns a fresh builder agent for one focused task."
4
+ ---
5
+
6
+ # /qualia-task — Single Task Builder
7
+
8
+ Build one thing properly. Fresh builder context, atomic commit, but no phase plan needed.
9
+
10
+ ## Usage
11
+ `/qualia-task` — describe what to build interactively
12
+ `/qualia-task {description}` — build it directly
13
+
14
+ ## When to Use
15
+ - One feature, 1-5 files, clear scope, 1-3 hours of work
16
+ - Adding a single feature, component, API route, or integration
17
+ - Refactoring one module
18
+ - Building something specific someone asked for
19
+
20
+ ## Process
21
+
22
+ ### 1. Clarify
23
+
24
+ If no description provided, ask: **"What do you want to build?"**
25
+
26
+ Then use AskUserQuestion:
27
+
28
+ ```
29
+ question: "How complex is this task?"
30
+ header: "Scope"
31
+ options:
32
+ - label: "Small (1-2hrs)"
33
+ description: "Single file or component, straightforward implementation"
34
+ - label: "Medium (2-3hrs)"
35
+ description: "Multiple files, some integration work, needs testing"
36
+ - label: "Large (3hrs+)"
37
+ description: "Significant feature, multiple components — use /qualia-plan instead"
38
+ ```
39
+
40
+ If "Large" — suggest `/qualia-plan` instead. Ask if they want to proceed anyway.
41
+
42
+ ### 2. Task Spec
43
+
44
+ Write a quick task spec (don't save to file, just confirm with user):
45
+
46
+ ```
47
+ ◆ QUALIA ► TASK
48
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
49
+
50
+ What: {what to build}
51
+ Files: {files to create/modify}
52
+ Done: {what "done" looks like}
53
+ ```
54
+
55
+ Ask: **"Good to build?"**
56
+
57
+ ### 3. Build
58
+
59
+ Spawn a builder agent with the task:
60
+
61
+ ```
62
+ Agent(subagent_type: "qualia-builder")
63
+
64
+ Task: {task description}
65
+ Files: {files to create/modify}
66
+ Done when: {completion criteria}
67
+
68
+ Context: Read PROJECT.md if it exists. Follow all rules (security, frontend, deployment).
69
+ ```
70
+
71
+ The builder runs in fresh context — reads before writing, follows rules, commits atomically.
72
+
73
+ ### 4. Verify
74
+
75
+ After the builder finishes:
76
+ - Run `npx tsc --noEmit` if TypeScript
77
+ - Quick smoke test if applicable
78
+ - Review what was built
79
+
80
+ ### 5. Report
81
+
82
+ ```
83
+ ◆ QUALIA ► TASK COMPLETE
84
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
85
+
86
+ Task {description}
87
+ Files {files changed}
88
+ Commit {commit hash}
89
+ Status ✓ Done
90
+ ```
91
+
92
+ Update `.planning/tracking.json` notes field if it exists.
@@ -41,7 +41,7 @@ Phase plan with success criteria:
41
41
  {@.planning/phase-{N}-verification.md}
42
42
 
43
43
  Verify this phase. Write report to .planning/phase-{N}-verification.md
44
- ", subagent_type="general-purpose", description="Verify phase {N}")
44
+ ", subagent_type="qualia-verifier", description="Verify phase {N}")
45
45
  ```
46
46
 
47
47
  ### 3. Present Results
@@ -0,0 +1,144 @@
1
+ #!/bin/bash
2
+ # Qualia Framework v2 — Hook Tests
3
+ # Run: bash tests/hooks.test.sh
4
+
5
+ PASS=0
6
+ FAIL=0
7
+ HOOKS_DIR="$(dirname "$0")/../hooks"
8
+
9
+ assert_exit() {
10
+ local name="$1" expected="$2" actual="$3"
11
+ if [ "$expected" = "$actual" ]; then
12
+ echo " ✓ $name"
13
+ PASS=$((PASS + 1))
14
+ else
15
+ echo " ✗ $name (expected exit $expected, got $actual)"
16
+ FAIL=$((FAIL + 1))
17
+ fi
18
+ }
19
+
20
+ echo "=== Hook Tests ==="
21
+ echo ""
22
+
23
+ # --- block-env-edit.sh ---
24
+ echo "block-env-edit:"
25
+
26
+ echo '{"tool_input":{"file_path":".env.local"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
27
+ assert_exit "blocks .env.local" 2 $?
28
+
29
+ echo '{"tool_input":{"file_path":".env.production"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
30
+ assert_exit "blocks .env.production" 2 $?
31
+
32
+ echo '{"tool_input":{"file_path":".env"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
33
+ assert_exit "blocks .env" 2 $?
34
+
35
+ echo '{"tool_input":{"file_path":"src/app.tsx"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
36
+ assert_exit "allows src/app.tsx" 0 $?
37
+
38
+ echo '{"tool_input":{"file_path":"components/Footer.tsx"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
39
+ assert_exit "allows components/Footer.tsx" 0 $?
40
+
41
+ # --- migration-guard.sh ---
42
+ echo ""
43
+ echo "migration-guard:"
44
+
45
+ echo '{"tool_input":{"file_path":"migrations/001.sql","content":"DROP TABLE users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
46
+ assert_exit "blocks DROP TABLE without IF EXISTS" 2 $?
47
+
48
+ echo '{"tool_input":{"file_path":"migrations/001.sql","content":"DROP TABLE IF EXISTS old_users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
49
+ assert_exit "allows DROP TABLE IF EXISTS" 0 $?
50
+
51
+ echo '{"tool_input":{"file_path":"migrations/002.sql","content":"DELETE FROM users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
52
+ assert_exit "blocks DELETE without WHERE" 2 $?
53
+
54
+ echo '{"tool_input":{"file_path":"migrations/003.sql","content":"TRUNCATE TABLE sessions;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
55
+ assert_exit "blocks TRUNCATE" 2 $?
56
+
57
+ echo '{"tool_input":{"file_path":"migrations/004.sql","content":"CREATE TABLE users (id uuid);"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
58
+ assert_exit "blocks CREATE TABLE without RLS" 2 $?
59
+
60
+ echo '{"tool_input":{"file_path":"migrations/005.sql","content":"ALTER TABLE users ADD COLUMN email text;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
61
+ assert_exit "allows safe ALTER TABLE" 0 $?
62
+
63
+ echo '{"tool_input":{"file_path":"src/app.tsx","content":"DROP TABLE users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
64
+ assert_exit "skips non-migration files" 0 $?
65
+
66
+ # --- branch-guard.sh ---
67
+ echo ""
68
+ echo "branch-guard:"
69
+
70
+ if [ -f "$HOOKS_DIR/branch-guard.sh" ]; then
71
+ echo " ✓ branch-guard.sh exists"
72
+ PASS=$((PASS + 1))
73
+ else
74
+ echo " ✗ branch-guard.sh missing"
75
+ FAIL=$((FAIL + 1))
76
+ fi
77
+
78
+ if grep -q 'ROLE' "$HOOKS_DIR/branch-guard.sh"; then
79
+ echo " ✓ checks ROLE variable"
80
+ PASS=$((PASS + 1))
81
+ else
82
+ echo " ✗ missing ROLE check"
83
+ FAIL=$((FAIL + 1))
84
+ fi
85
+
86
+ if grep -q 'z "$ROLE"' "$HOOKS_DIR/branch-guard.sh"; then
87
+ echo " ✓ defaults to deny on missing ROLE"
88
+ PASS=$((PASS + 1))
89
+ else
90
+ echo " ✗ missing empty-ROLE deny"
91
+ FAIL=$((FAIL + 1))
92
+ fi
93
+
94
+ # --- pre-push.sh ---
95
+ echo ""
96
+ echo "pre-push:"
97
+
98
+ if grep -q 'command -v python3' "$HOOKS_DIR/pre-push.sh"; then
99
+ echo " ✓ checks for python3 availability"
100
+ PASS=$((PASS + 1))
101
+ else
102
+ echo " ✗ missing python3 check"
103
+ FAIL=$((FAIL + 1))
104
+ fi
105
+
106
+ if grep -q 'qualia-push-err' "$HOOKS_DIR/pre-push.sh"; then
107
+ echo " ✓ captures python3 errors"
108
+ PASS=$((PASS + 1))
109
+ else
110
+ echo " ✗ missing python3 error capture"
111
+ FAIL=$((FAIL + 1))
112
+ fi
113
+
114
+ # --- pre-deploy-gate.sh ---
115
+ echo ""
116
+ echo "pre-deploy-gate:"
117
+
118
+ if [ -f "$HOOKS_DIR/pre-deploy-gate.sh" ]; then
119
+ echo " ✓ pre-deploy-gate.sh exists"
120
+ PASS=$((PASS + 1))
121
+ else
122
+ echo " ✗ pre-deploy-gate.sh missing"
123
+ FAIL=$((FAIL + 1))
124
+ fi
125
+
126
+ if grep -q 'tsc --noEmit' "$HOOKS_DIR/pre-deploy-gate.sh"; then
127
+ echo " ✓ runs TypeScript check"
128
+ PASS=$((PASS + 1))
129
+ else
130
+ echo " ✗ missing TypeScript check"
131
+ FAIL=$((FAIL + 1))
132
+ fi
133
+
134
+ if grep -q 'service_role' "$HOOKS_DIR/pre-deploy-gate.sh"; then
135
+ echo " ✓ checks for service_role leaks"
136
+ PASS=$((PASS + 1))
137
+ else
138
+ echo " ✗ missing service_role check"
139
+ FAIL=$((FAIL + 1))
140
+ fi
141
+
142
+ echo ""
143
+ echo "=== Results: $PASS passed, $FAIL failed ==="
144
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1
package/install.sh DELETED
@@ -1,223 +0,0 @@
1
- #!/bin/bash
2
- # Qualia Framework v2 — Installer
3
- # Installs skills, agents, rules, hooks, templates, status line, and configures settings.json
4
-
5
- set -e
6
-
7
- FRAMEWORK_DIR="$(cd "$(dirname "$0")" && pwd)"
8
- CLAUDE_DIR="$HOME/.claude"
9
-
10
- echo "◆ Qualia Framework v2"
11
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
12
- echo " Installing to $CLAUDE_DIR"
13
- echo ""
14
-
15
- # Skills
16
- echo " Installing skills..."
17
- for skill_dir in "$FRAMEWORK_DIR"/skills/*/; do
18
- skill_name=$(basename "$skill_dir")
19
- mkdir -p "$CLAUDE_DIR/skills/$skill_name"
20
- cp "$skill_dir/SKILL.md" "$CLAUDE_DIR/skills/$skill_name/SKILL.md"
21
- echo " ✓ $skill_name"
22
- done
23
-
24
- # Agents
25
- echo " Installing agents..."
26
- mkdir -p "$CLAUDE_DIR/agents"
27
- for agent in "$FRAMEWORK_DIR"/agents/*.md; do
28
- cp "$agent" "$CLAUDE_DIR/agents/"
29
- echo " ✓ $(basename "$agent")"
30
- done
31
-
32
- # Rules
33
- echo " Installing rules..."
34
- mkdir -p "$CLAUDE_DIR/rules"
35
- for rule in "$FRAMEWORK_DIR"/rules/*.md; do
36
- cp "$rule" "$CLAUDE_DIR/rules/"
37
- echo " ✓ $(basename "$rule")"
38
- done
39
-
40
- # Hook scripts
41
- echo " Installing hook scripts..."
42
- mkdir -p "$CLAUDE_DIR/hooks"
43
- for hook in "$FRAMEWORK_DIR"/hooks/*.sh; do
44
- cp "$hook" "$CLAUDE_DIR/hooks/"
45
- chmod +x "$CLAUDE_DIR/hooks/$(basename "$hook")"
46
- echo " ✓ $(basename "$hook")"
47
- done
48
-
49
- # Status line
50
- echo " Installing status line..."
51
- cp "$FRAMEWORK_DIR/statusline.sh" "$CLAUDE_DIR/statusline.sh"
52
- chmod +x "$CLAUDE_DIR/statusline.sh"
53
- echo " ✓ statusline.sh"
54
-
55
- # Templates
56
- echo " Installing templates..."
57
- mkdir -p "$CLAUDE_DIR/qualia-templates"
58
- for tmpl in "$FRAMEWORK_DIR"/templates/*; do
59
- cp "$tmpl" "$CLAUDE_DIR/qualia-templates/"
60
- echo " ✓ $(basename "$tmpl")"
61
- done
62
-
63
- # CLAUDE.md (user-level — applies to all projects)
64
- echo " Installing CLAUDE.md..."
65
- cp "$FRAMEWORK_DIR/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md"
66
- echo " ✓ CLAUDE.md"
67
-
68
- # Guide
69
- cp "$FRAMEWORK_DIR/guide.md" "$CLAUDE_DIR/qualia-guide.md"
70
- echo " ✓ guide.md"
71
-
72
- # Configure settings.json with hooks, status line, and env
73
- echo ""
74
- echo " Configuring settings.json..."
75
-
76
- python3 << 'PYEOF'
77
- import json, os
78
-
79
- settings_path = os.path.expanduser("~/.claude/settings.json")
80
-
81
- # Load existing settings or start fresh
82
- if os.path.exists(settings_path):
83
- with open(settings_path) as f:
84
- settings = json.load(f)
85
- else:
86
- settings = {}
87
-
88
- # Env vars
89
- settings.setdefault("env", {})
90
- settings["env"].update({
91
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
92
- "CLAUDE_CODE_DISABLE_AUTO_MEMORY": "0",
93
- "MAX_MCP_OUTPUT_TOKENS": "25000",
94
- "CLAUDE_CODE_NO_FLICKER": "1"
95
- })
96
-
97
- # Status line — teal branded, 2-line
98
- settings["statusLine"] = {
99
- "type": "command",
100
- "command": "~/.claude/statusline.sh"
101
- }
102
-
103
- # Spinner verbs — Qualia branded
104
- settings["spinnerVerbs"] = {
105
- "mode": "replace",
106
- "verbs": [
107
- "Qualia-fying", "Solution-ing", "Teal-crafting", "Vibe-forging",
108
- "Shipping", "Wiring", "Polishing", "Verifying",
109
- "Orchestrating", "Architecting", "Deploying", "Hardening"
110
- ]
111
- }
112
-
113
- # Spinner tips — Qualia tips
114
- settings["spinnerTipsOverride"] = {
115
- "excludeDefault": True,
116
- "tips": [
117
- "◆ Lost? Type /qualia for the next step",
118
- "◆ Small fix? Use /qualia-quick to skip planning",
119
- "◆ End of day? /qualia-report before you clock out",
120
- "◆ Context isolation: every task gets a fresh AI brain",
121
- "◆ The verifier doesn't trust claims — it greps the code",
122
- "◆ Plans are prompts — the plan IS what the builder reads",
123
- "◆ Feature branches only — never push to main",
124
- "◆ Read before write — no exceptions",
125
- "◆ MVP first — build what's asked, nothing extra",
126
- "◆ tracking.json syncs to ERP on every push"
127
- ]
128
- }
129
-
130
- # Hooks
131
- hooks_dir = os.path.expanduser("~/.claude/hooks")
132
- settings["hooks"] = {
133
- "PreToolUse": [
134
- {
135
- "matcher": "Bash",
136
- "hooks": [{
137
- "type": "command",
138
- "if": "Bash(git push*)",
139
- "command": f"{hooks_dir}/branch-guard.sh",
140
- "timeout": 10,
141
- "statusMessage": "◆ Checking branch permissions..."
142
- }]
143
- },
144
- {
145
- "matcher": "Edit|Write",
146
- "hooks": [{
147
- "type": "command",
148
- "if": "Edit(*.env*)",
149
- "command": f"{hooks_dir}/block-env-edit.sh",
150
- "timeout": 5,
151
- "statusMessage": "◆ Checking file permissions..."
152
- }]
153
- }
154
- ],
155
- "PostToolUse": [
156
- {
157
- "matcher": "Bash",
158
- "hooks": [{
159
- "type": "command",
160
- "if": "Bash(vercel --prod*)",
161
- "command": f"{hooks_dir}/pre-deploy-gate.sh",
162
- "timeout": 120,
163
- "statusMessage": "◆ Running quality gates..."
164
- }]
165
- }
166
- ],
167
- "PreCompact": [
168
- {
169
- "matcher": "compact",
170
- "hooks": [{
171
- "type": "command",
172
- "command": f"{hooks_dir}/pre-compact.sh",
173
- "timeout": 15,
174
- "statusMessage": "◆ Saving state..."
175
- }]
176
- }
177
- ],
178
- "SubagentStart": [
179
- {
180
- "matcher": ".*",
181
- "hooks": [{
182
- "type": "command",
183
- "command": "echo '{\"additionalContext\": \"◆ Qualia agent spawned\"}'"
184
- }]
185
- }
186
- ]
187
- }
188
-
189
- # Permissions
190
- settings.setdefault("permissions", {})
191
- settings["permissions"].setdefault("allow", [])
192
- settings["permissions"].setdefault("deny", [
193
- "Read(./.env)",
194
- "Read(./.env.*)",
195
- "Read(./secrets/**)"
196
- ])
197
-
198
- # Effort level
199
- settings["effortLevel"] = "high"
200
-
201
- with open(settings_path, "w") as f:
202
- json.dump(settings, f, indent=2)
203
-
204
- print(" ✓ Hooks registered (branch-guard, env-block, deploy-gate, pre-compact, subagent-label)")
205
- print(" ✓ Status line configured (2-line teal branded)")
206
- print(" ✓ Spinner verbs: Qualia branded")
207
- print(" ✓ Spinner tips: Qualia tips")
208
- print(" ✓ Environment variables set")
209
- PYEOF
210
-
211
- echo ""
212
- echo "◆ Installed ✓"
213
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
214
- echo " Skills: 10"
215
- echo " Agents: 3 (planner, builder, verifier)"
216
- echo " Hooks: 4 (branch-guard, env-block, deploy-gate, pre-compact)"
217
- echo " Rules: 3 (security, frontend, deployment)"
218
- echo " Templates: 4"
219
- echo " Status line: ✓"
220
- echo " CLAUDE.md: ✓ (user-level)"
221
- echo ""
222
- echo " Restart Claude Code, then type /qualia in any project."
223
- echo ""