@arthai/agents 1.0.5 → 1.0.6
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/README.md +33 -3
- package/VERSION +1 -1
- package/agents/troubleshooter.md +132 -0
- package/bin/cli.js +297 -0
- package/bundles/canvas.json +1 -1
- package/bundles/compass.json +1 -1
- package/bundles/counsel.json +1 -0
- package/bundles/cruise.json +1 -1
- package/bundles/forge.json +12 -1
- package/bundles/prism.json +1 -0
- package/bundles/scalpel.json +5 -2
- package/bundles/sentinel.json +8 -2
- package/bundles/shield.json +1 -0
- package/bundles/spark.json +1 -0
- package/compiler.sh +14 -0
- package/dist/plugins/canvas/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/canvas/VERSION +1 -0
- package/dist/plugins/canvas/commands/planning.md +100 -11
- package/dist/plugins/canvas/hooks/hooks.json +16 -0
- package/dist/plugins/canvas/hooks/project-setup.sh +109 -0
- package/dist/plugins/canvas/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/canvas/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/compass/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/compass/VERSION +1 -0
- package/dist/plugins/compass/commands/planning.md +100 -11
- package/dist/plugins/compass/hooks/hooks.json +16 -0
- package/dist/plugins/compass/hooks/project-setup.sh +109 -0
- package/dist/plugins/compass/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/compass/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/counsel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/counsel/VERSION +1 -0
- package/dist/plugins/counsel/hooks/hooks.json +10 -0
- package/dist/plugins/counsel/hooks/project-setup.sh +109 -0
- package/dist/plugins/counsel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/counsel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/cruise/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/cruise/VERSION +1 -0
- package/dist/plugins/cruise/hooks/hooks.json +16 -0
- package/dist/plugins/cruise/hooks/project-setup.sh +109 -0
- package/dist/plugins/cruise/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/cruise/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/forge/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/forge/VERSION +1 -0
- package/dist/plugins/forge/agents/troubleshooter.md +132 -0
- package/dist/plugins/forge/commands/implement.md +99 -1
- package/dist/plugins/forge/commands/planning.md +100 -11
- package/dist/plugins/forge/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/forge/hooks/hooks.json +22 -0
- package/dist/plugins/forge/hooks/project-setup.sh +109 -0
- package/dist/plugins/forge/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/forge/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/prime/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prime/VERSION +1 -0
- package/dist/plugins/prime/agents/troubleshooter.md +132 -0
- package/dist/plugins/prime/commands/calibrate.md +20 -0
- package/dist/plugins/prime/commands/ci-fix.md +36 -0
- package/dist/plugins/prime/commands/fix.md +23 -0
- package/dist/plugins/prime/commands/implement.md +99 -1
- package/dist/plugins/prime/commands/planning.md +100 -11
- package/dist/plugins/prime/commands/qa-incident.md +54 -0
- package/dist/plugins/prime/commands/restart.md +186 -30
- package/dist/plugins/prime/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/prime/hooks/hooks.json +60 -0
- package/dist/plugins/prime/hooks/post-config-change-restart-reminder.sh +86 -0
- package/dist/plugins/prime/hooks/post-server-crash-watch.sh +120 -0
- package/dist/plugins/prime/hooks/pre-server-port-guard.sh +110 -0
- package/dist/plugins/prime/hooks/project-setup.sh +109 -0
- package/dist/plugins/prime/hooks/sync-agents.sh +99 -12
- package/dist/plugins/prime/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/prime/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/prism/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prism/VERSION +1 -0
- package/dist/plugins/prism/commands/qa-incident.md +54 -0
- package/dist/plugins/prism/hooks/hooks.json +12 -0
- package/dist/plugins/prism/hooks/project-setup.sh +109 -0
- package/dist/plugins/prism/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/prism/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/scalpel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/scalpel/VERSION +1 -0
- package/dist/plugins/scalpel/agents/troubleshooter.md +132 -0
- package/dist/plugins/scalpel/commands/ci-fix.md +36 -0
- package/dist/plugins/scalpel/commands/fix.md +23 -0
- package/dist/plugins/scalpel/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/scalpel/hooks/hooks.json +24 -0
- package/dist/plugins/scalpel/hooks/project-setup.sh +109 -0
- package/dist/plugins/scalpel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/scalpel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/sentinel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/sentinel/VERSION +1 -0
- package/dist/plugins/sentinel/agents/troubleshooter.md +132 -0
- package/dist/plugins/sentinel/commands/restart.md +186 -30
- package/dist/plugins/sentinel/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/sentinel/hooks/hooks.json +64 -0
- package/dist/plugins/sentinel/hooks/post-config-change-restart-reminder.sh +86 -0
- package/dist/plugins/sentinel/hooks/post-server-crash-watch.sh +120 -0
- package/dist/plugins/sentinel/hooks/pre-server-port-guard.sh +110 -0
- package/dist/plugins/sentinel/hooks/project-setup.sh +109 -0
- package/dist/plugins/sentinel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/sentinel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/shield/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/shield/VERSION +1 -0
- package/dist/plugins/shield/hooks/hooks.json +22 -12
- package/dist/plugins/shield/hooks/project-setup.sh +109 -0
- package/dist/plugins/shield/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/shield/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/spark/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/spark/VERSION +1 -0
- package/dist/plugins/spark/commands/calibrate.md +20 -0
- package/dist/plugins/spark/hooks/hooks.json +10 -0
- package/dist/plugins/spark/hooks/project-setup.sh +109 -0
- package/dist/plugins/spark/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/spark/templates/CLAUDE.md.template +111 -0
- package/hook-defs.json +31 -0
- package/hooks/escalation-guard.sh +177 -0
- package/hooks/post-config-change-restart-reminder.sh +86 -0
- package/hooks/post-server-crash-watch.sh +120 -0
- package/hooks/pre-server-port-guard.sh +110 -0
- package/hooks/project-setup.sh +109 -0
- package/hooks/sync-agents.sh +99 -12
- package/install.sh +2 -2
- package/package.json +1 -1
- package/portable.manifest +7 -1
- package/skills/calibrate/SKILL.md +20 -0
- package/skills/ci-fix/SKILL.md +36 -0
- package/skills/fix/SKILL.md +23 -0
- package/skills/implement/SKILL.md +99 -1
- package/skills/license/SKILL.md +159 -0
- package/skills/planning/SKILL.md +100 -11
- package/skills/qa-incident/SKILL.md +54 -0
- package/skills/restart/SKILL.md +187 -31
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse hook (Bash): Detect server start commands and check for crash loops.
|
|
3
|
+
# After a server start is detected, waits briefly then verifies the process is
|
|
4
|
+
# still running and the port is responding. Catches services that start then die.
|
|
5
|
+
#
|
|
6
|
+
# stdout is injected as context.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
COMMAND="${CLAUDE_TOOL_INPUT_COMMAND:-}"
|
|
11
|
+
if [ -z "$COMMAND" ] && [ -n "${CLAUDE_TOOL_INPUT:-}" ]; then
|
|
12
|
+
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('command',''))" 2>/dev/null) || true
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
[ -z "$COMMAND" ] && exit 0
|
|
16
|
+
|
|
17
|
+
# Only check commands that ran successfully
|
|
18
|
+
EXIT_CODE="${CLAUDE_TOOL_RESULT_EXIT_CODE:-0}"
|
|
19
|
+
[ "$EXIT_CODE" != "0" ] && exit 0
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Detect server start commands and extract ports
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
PORT=""
|
|
26
|
+
SERVICE=""
|
|
27
|
+
|
|
28
|
+
# npm/pnpm/yarn dev/start
|
|
29
|
+
if echo "$COMMAND" | grep -qE '\b(npm|pnpm|yarn)\s+run\s+(dev|start|serve)\b'; then
|
|
30
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
31
|
+
PORT="${PORT:-3000}"
|
|
32
|
+
SERVICE="Node.js dev server"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# next dev
|
|
36
|
+
if echo "$COMMAND" | grep -qE '\bnext\s+dev\b'; then
|
|
37
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
38
|
+
PORT="${PORT:-3000}"
|
|
39
|
+
SERVICE="Next.js dev server"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# uvicorn
|
|
43
|
+
if echo "$COMMAND" | grep -qE '\buvicorn\b'; then
|
|
44
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
45
|
+
PORT="${PORT:-8000}"
|
|
46
|
+
SERVICE="Uvicorn"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# gunicorn
|
|
50
|
+
if echo "$COMMAND" | grep -qE '\bgunicorn\b'; then
|
|
51
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-b\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
52
|
+
if [ -z "$PORT" ]; then
|
|
53
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-bind\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
54
|
+
fi
|
|
55
|
+
PORT="${PORT:-8000}"
|
|
56
|
+
SERVICE="Gunicorn"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# flask run
|
|
60
|
+
if echo "$COMMAND" | grep -qE '\bflask\s+run\b'; then
|
|
61
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
62
|
+
PORT="${PORT:-5000}"
|
|
63
|
+
SERVICE="Flask"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# docker compose up
|
|
67
|
+
if echo "$COMMAND" | grep -qE '\bdocker\s+compose\s+up\b'; then
|
|
68
|
+
SERVICE="Docker Compose services"
|
|
69
|
+
# For docker compose, check container status instead of port
|
|
70
|
+
sleep 8
|
|
71
|
+
down_containers=$(docker compose ps --format '{{.Name}} {{.Status}}' 2>/dev/null | grep -viE 'Up|running' | head -5) || true
|
|
72
|
+
if [ -n "$down_containers" ]; then
|
|
73
|
+
echo "CRASH DETECTED — Docker containers not healthy after 8s:"
|
|
74
|
+
echo "$down_containers"
|
|
75
|
+
echo "Check logs: docker compose logs --tail=30"
|
|
76
|
+
fi
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# rails server
|
|
81
|
+
if echo "$COMMAND" | grep -qE '\brails\s+s(erver)?\b'; then
|
|
82
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-p\s+([0-9]+)' | awk '{print $2}')
|
|
83
|
+
PORT="${PORT:-3000}"
|
|
84
|
+
SERVICE="Rails server"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# No server start detected
|
|
88
|
+
[ -z "$SERVICE" ] && exit 0
|
|
89
|
+
[ -z "$PORT" ] && exit 0
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Wait and check for crash loop
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
sleep 8
|
|
96
|
+
|
|
97
|
+
# Check if process is still listening on the port
|
|
98
|
+
pid=$(lsof -ti:"$PORT" 2>/dev/null | head -1) || true
|
|
99
|
+
|
|
100
|
+
if [ -z "$pid" ]; then
|
|
101
|
+
echo "CRASH DETECTED — $SERVICE (port $PORT) is no longer running after 8s."
|
|
102
|
+
echo "The process started but has since exited. Check the terminal output for errors."
|
|
103
|
+
echo "Common causes: missing env vars, port conflict, dependency errors, syntax errors."
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# Process is alive — try a quick HTTP health check
|
|
108
|
+
http_status=$(timeout 5 curl -sf -o /dev/null -w "%{http_code}" "http://localhost:$PORT/" 2>/dev/null) || http_status="no_response"
|
|
109
|
+
|
|
110
|
+
if [ "$http_status" = "no_response" ]; then
|
|
111
|
+
# Process exists but not responding to HTTP — might be starting up or non-HTTP
|
|
112
|
+
echo "$SERVICE (port $PORT): process alive (PID $pid) but not responding to HTTP yet. May still be starting."
|
|
113
|
+
elif echo "$http_status" | grep -qE '^[2345]'; then
|
|
114
|
+
# Any HTTP response means the server is up
|
|
115
|
+
: # Silent success — don't spam on healthy starts
|
|
116
|
+
else
|
|
117
|
+
echo "$SERVICE (port $PORT): process alive but returned HTTP $http_status."
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
exit 0
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse hook (Bash): Check port availability before server start commands.
|
|
3
|
+
# Detects server start commands and warns if the target port is already occupied
|
|
4
|
+
# by an unexpected process.
|
|
5
|
+
#
|
|
6
|
+
# Exit 0 = allow the command
|
|
7
|
+
# Exit 2 = block the command (stdout shown as reason)
|
|
8
|
+
# stdout = injected as context (warnings)
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
COMMAND="${CLAUDE_TOOL_INPUT_COMMAND:-}"
|
|
13
|
+
if [ -z "$COMMAND" ] && [ -n "${CLAUDE_TOOL_INPUT:-}" ]; then
|
|
14
|
+
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('command',''))" 2>/dev/null) || true
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
[ -z "$COMMAND" ] && exit 0
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Detect server start commands and extract ports
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
declare -a PORTS=()
|
|
24
|
+
|
|
25
|
+
# npm/pnpm/yarn dev/start — default port 3000 unless --port specified
|
|
26
|
+
if echo "$COMMAND" | grep -qE '\b(npm|pnpm|yarn)\s+run\s+(dev|start|serve)\b'; then
|
|
27
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
28
|
+
if [ -z "$port" ]; then
|
|
29
|
+
port=$(echo "$COMMAND" | grep -oE '\bp(ort)?\s*=?\s*([0-9]{4,5})' | grep -oE '[0-9]+')
|
|
30
|
+
fi
|
|
31
|
+
PORTS+=("${port:-3000}")
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# next dev — default port 3000
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\bnext\s+dev\b'; then
|
|
36
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
37
|
+
PORTS+=("${port:-3000}")
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# vite — default port 5173
|
|
41
|
+
if echo "$COMMAND" | grep -qE '\bvite\b' && ! echo "$COMMAND" | grep -qE '\bvite\s+build\b'; then
|
|
42
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
43
|
+
PORTS+=("${port:-5173}")
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# uvicorn — default port 8000
|
|
47
|
+
if echo "$COMMAND" | grep -qE '\buvicorn\b'; then
|
|
48
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
49
|
+
PORTS+=("${port:-8000}")
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# gunicorn — default port 8000
|
|
53
|
+
if echo "$COMMAND" | grep -qE '\bgunicorn\b'; then
|
|
54
|
+
port=$(echo "$COMMAND" | grep -oE '\-b\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
55
|
+
if [ -z "$port" ]; then
|
|
56
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-bind\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
57
|
+
fi
|
|
58
|
+
PORTS+=("${port:-8000}")
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# flask run — default port 5000
|
|
62
|
+
if echo "$COMMAND" | grep -qE '\bflask\s+run\b'; then
|
|
63
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
64
|
+
PORTS+=("${port:-5000}")
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# docker compose up — check compose file for ports
|
|
68
|
+
if echo "$COMMAND" | grep -qE '\bdocker\s+compose\s+up\b'; then
|
|
69
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
70
|
+
if [ -f "$PROJECT_DIR/docker-compose.yml" ]; then
|
|
71
|
+
# Extract host ports from ports: mappings (e.g., "3000:3000", "5432:5432")
|
|
72
|
+
compose_ports=$(grep -oE '^\s*-\s*"?([0-9]+):' "$PROJECT_DIR/docker-compose.yml" 2>/dev/null | grep -oE '[0-9]+' | head -5) || true
|
|
73
|
+
for p in $compose_ports; do
|
|
74
|
+
PORTS+=("$p")
|
|
75
|
+
done
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# rails server — default port 3000
|
|
80
|
+
if echo "$COMMAND" | grep -qE '\brails\s+s(erver)?\b'; then
|
|
81
|
+
port=$(echo "$COMMAND" | grep -oE '\-p\s+([0-9]+)' | awk '{print $2}')
|
|
82
|
+
PORTS+=("${port:-3000}")
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# go run with -addr or explicit port
|
|
86
|
+
if echo "$COMMAND" | grep -qE '\bgo\s+run\b'; then
|
|
87
|
+
port=$(echo "$COMMAND" | grep -oE ':([0-9]{4,5})' | head -1 | tr -d ':')
|
|
88
|
+
[ -n "$port" ] && PORTS+=("$port")
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# No server command detected
|
|
92
|
+
[ ${#PORTS[@]} -eq 0 ] && exit 0
|
|
93
|
+
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# Check each port for conflicts
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
for port in "${PORTS[@]}"; do
|
|
99
|
+
[ -z "$port" ] && continue
|
|
100
|
+
|
|
101
|
+
pid=$(lsof -ti:"$port" 2>/dev/null | head -1) || true
|
|
102
|
+
if [ -n "$pid" ]; then
|
|
103
|
+
proc_name=$(ps -p "$pid" -o comm= 2>/dev/null) || proc_name="unknown"
|
|
104
|
+
echo "PORT CONFLICT — port $port is already in use by $proc_name (PID $pid)."
|
|
105
|
+
echo "Kill it first: lsof -ti:$port | xargs kill -9"
|
|
106
|
+
echo "Or use a different port."
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
exit 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# hooks/project-setup.sh — SessionStart hook: first-run project setup for marketplace installs.
|
|
3
|
+
#
|
|
4
|
+
# Runs on every SessionStart. Checks for marker file .claude/.toolkit-setup-done.
|
|
5
|
+
# If missing (or version is stale): creates CLAUDE.md from template, injects managed block,
|
|
6
|
+
# updates .gitignore with toolkit markers.
|
|
7
|
+
#
|
|
8
|
+
# Templates are read from ${CLAUDE_PLUGIN_ROOT}/templates/ (bundled with the plugin).
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
13
|
+
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-}"
|
|
14
|
+
MARKER_FILE="$PROJECT_DIR/.claude/.toolkit-setup-done"
|
|
15
|
+
|
|
16
|
+
# Exit silently if CLAUDE_PLUGIN_ROOT is not set (not running from a plugin context)
|
|
17
|
+
if [ -z "$PLUGIN_ROOT" ]; then
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
TEMPLATES_DIR="$PLUGIN_ROOT/templates"
|
|
22
|
+
TEMPLATE_CLAUDE="$TEMPLATES_DIR/CLAUDE.md.template"
|
|
23
|
+
TEMPLATE_BLOCK="$TEMPLATES_DIR/CLAUDE.md.managed-block"
|
|
24
|
+
|
|
25
|
+
# Exit silently if templates are not bundled
|
|
26
|
+
if [ ! -f "$TEMPLATE_CLAUDE" ] || [ ! -f "$TEMPLATE_BLOCK" ]; then
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Read toolkit version from VERSION file (bundled alongside plugin)
|
|
31
|
+
TOOLKIT_VERSION="0.0.0"
|
|
32
|
+
if [ -f "$PLUGIN_ROOT/VERSION" ]; then
|
|
33
|
+
TOOLKIT_VERSION=$(cat "$PLUGIN_ROOT/VERSION" 2>/dev/null | tr -d '[:space:]' || echo "0.0.0")
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
MANAGED_START="<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->"
|
|
37
|
+
MANAGED_END="<!-- <<< claude-agents toolkit <<< -->"
|
|
38
|
+
GITIGNORE_START="# >>> claude-agents managed (DO NOT EDIT THIS BLOCK) >>>"
|
|
39
|
+
|
|
40
|
+
# Check marker file — skip if current version is already set up
|
|
41
|
+
if [ -f "$MARKER_FILE" ]; then
|
|
42
|
+
STORED_VERSION=$(cat "$MARKER_FILE" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
43
|
+
if [ "$STORED_VERSION" = "$TOOLKIT_VERSION" ]; then
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
CLAUDE_MD="$PROJECT_DIR/CLAUDE.md"
|
|
49
|
+
GITIGNORE="$PROJECT_DIR/.gitignore"
|
|
50
|
+
|
|
51
|
+
# 1. Create CLAUDE.md from template if it doesn't exist (never overwrite existing)
|
|
52
|
+
if [ ! -f "$CLAUDE_MD" ]; then
|
|
53
|
+
PROJECT_NAME=$(basename "$PROJECT_DIR")
|
|
54
|
+
sed "s/{{PROJECT_NAME}}/$PROJECT_NAME/g" "$TEMPLATE_CLAUDE" > "$CLAUDE_MD"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# 2. Inject managed block into CLAUDE.md if missing, or update if version is stale
|
|
58
|
+
if [ -f "$CLAUDE_MD" ]; then
|
|
59
|
+
BLOCK_CONTENT=$(cat "$TEMPLATE_BLOCK")
|
|
60
|
+
NEW_BLOCK=$(printf '%s\n<!-- version: %s -->\n%s\n%s' \
|
|
61
|
+
"$MANAGED_START" "$TOOLKIT_VERSION" "$BLOCK_CONTENT" "$MANAGED_END")
|
|
62
|
+
|
|
63
|
+
if ! grep -qF "$MANAGED_START" "$CLAUDE_MD"; then
|
|
64
|
+
# Block missing — append it
|
|
65
|
+
printf '\n\n%s\n' "$NEW_BLOCK" >> "$CLAUDE_MD"
|
|
66
|
+
else
|
|
67
|
+
# Block exists — update if version changed
|
|
68
|
+
EXISTING_VERSION=$(grep -o '<!-- version: [^>]* -->' "$CLAUDE_MD" 2>/dev/null | head -1 | sed 's/<!-- version: //;s/ -->//' | tr -d '[:space:]' || echo "")
|
|
69
|
+
if [ "$EXISTING_VERSION" != "$TOOLKIT_VERSION" ]; then
|
|
70
|
+
# Replace block contents between markers
|
|
71
|
+
tmp=$(mktemp)
|
|
72
|
+
in_block=false
|
|
73
|
+
wrote_block=false
|
|
74
|
+
while IFS= read -r line; do
|
|
75
|
+
if echo "$line" | grep -qF "$MANAGED_START"; then
|
|
76
|
+
in_block=true
|
|
77
|
+
printf '%s\n' "$NEW_BLOCK" >> "$tmp"
|
|
78
|
+
wrote_block=true
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
if echo "$line" | grep -qF "$MANAGED_END"; then
|
|
82
|
+
in_block=false
|
|
83
|
+
continue
|
|
84
|
+
fi
|
|
85
|
+
if ! $in_block; then
|
|
86
|
+
echo "$line" >> "$tmp"
|
|
87
|
+
fi
|
|
88
|
+
done < "$CLAUDE_MD"
|
|
89
|
+
mv "$tmp" "$CLAUDE_MD"
|
|
90
|
+
fi
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# 3. Update .gitignore with toolkit marker block if missing
|
|
95
|
+
if [ ! -f "$GITIGNORE" ] || ! grep -qF "$GITIGNORE_START" "$GITIGNORE" 2>/dev/null; then
|
|
96
|
+
GITIGNORE_BLOCK=$(printf '%s\n.claude/.toolkit-last-seen-sha\n.claude/.toolkit-setup-done\n.claude/.claude-agents.conf\n%s' \
|
|
97
|
+
"$GITIGNORE_START" "# <<< claude-agents managed <<<")
|
|
98
|
+
if [ ! -f "$GITIGNORE" ]; then
|
|
99
|
+
printf '%s\n' "$GITIGNORE_BLOCK" > "$GITIGNORE"
|
|
100
|
+
else
|
|
101
|
+
printf '\n\n%s\n' "$GITIGNORE_BLOCK" >> "$GITIGNORE"
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# 4. Write marker file with current version
|
|
106
|
+
mkdir -p "$PROJECT_DIR/.claude"
|
|
107
|
+
printf '%s\n' "$TOOLKIT_VERSION" > "$MARKER_FILE"
|
|
108
|
+
|
|
109
|
+
exit 0
|
|
@@ -22,8 +22,9 @@ if [ ! -d "$AGENTS_DIR/.git" ]; then
|
|
|
22
22
|
exit 0
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
|
-
# Exit silently if no license
|
|
26
|
-
|
|
25
|
+
# Exit silently if no license found in any path
|
|
26
|
+
ARTHAI_LICENSE_PATH="$REAL_HOME/.arthai/license"
|
|
27
|
+
if [ ! -f "$LICENSE_FILE" ] && [ ! -f "$ARTHAI_LICENSE_PATH" ] && [ -z "${ARTHAI_LICENSE_KEY:-}" ]; then
|
|
27
28
|
exit 0
|
|
28
29
|
fi
|
|
29
30
|
|
|
@@ -108,6 +109,27 @@ fi
|
|
|
108
109
|
|
|
109
110
|
# --- Step 2: Check license (with revocation enforcement) ---
|
|
110
111
|
NOW=$(date +%s)
|
|
112
|
+
WORKER_URL="https://license-worker.muddassar-shaikh.workers.dev"
|
|
113
|
+
|
|
114
|
+
# Resolve license key: ~/.claude-agents/.license takes priority (existing clone-install users),
|
|
115
|
+
# fall back to ~/.arthai/license (npm activate users).
|
|
116
|
+
ARTHAI_LICENSE_KEY_VALUE="${ARTHAI_LICENSE_KEY:-}"
|
|
117
|
+
RESOLVED_KEY=""
|
|
118
|
+
if [ -n "$ARTHAI_LICENSE_KEY_VALUE" ]; then
|
|
119
|
+
RESOLVED_KEY="$ARTHAI_LICENSE_KEY_VALUE"
|
|
120
|
+
elif [ -f "$LICENSE_FILE" ]; then
|
|
121
|
+
RESOLVED_KEY=$(cat "$LICENSE_FILE" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
122
|
+
elif [ -f "$REAL_HOME/.arthai/license" ]; then
|
|
123
|
+
RESOLVED_KEY=$(cat "$REAL_HOME/.arthai/license" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Validate key format before using it in any JSON payload — prevents JSON injection
|
|
127
|
+
# via a crafted key value in the env var or license file.
|
|
128
|
+
KEY_FORMAT='^ARTH-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$'
|
|
129
|
+
if [ -n "$RESOLVED_KEY" ] && ! echo "$RESOLVED_KEY" | grep -qE "$KEY_FORMAT"; then
|
|
130
|
+
# Key has invalid format — don't use it for Worker call or local check
|
|
131
|
+
RESOLVED_KEY=""
|
|
132
|
+
fi
|
|
111
133
|
|
|
112
134
|
# Detect if authorized-keys.txt changed in the pull — force re-check if so
|
|
113
135
|
AK_HASH_FILE="$AGENTS_DIR/.ak-hash"
|
|
@@ -128,6 +150,49 @@ fi
|
|
|
128
150
|
# Store current hash for next comparison
|
|
129
151
|
[ -n "$AK_CURRENT_HASH" ] && echo "$AK_CURRENT_HASH" > "$AK_HASH_FILE" 2>/dev/null || true
|
|
130
152
|
|
|
153
|
+
# validate_with_worker: call Worker /validate with the resolved key.
|
|
154
|
+
# Sets WORKER_RESULT: "valid", "invalid" (definitive), or "network_error".
|
|
155
|
+
validate_with_worker() {
|
|
156
|
+
local key="$1"
|
|
157
|
+
if [ -z "$key" ]; then
|
|
158
|
+
WORKER_RESULT="invalid"
|
|
159
|
+
return
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
local payload="{\"key\":\"$key\"}"
|
|
163
|
+
local response
|
|
164
|
+
local curl_exit
|
|
165
|
+
|
|
166
|
+
# Pass payload via stdin (--data @-) so the key is not visible in the process list
|
|
167
|
+
response=$(printf '%s' "$payload" | curl \
|
|
168
|
+
--silent \
|
|
169
|
+
--max-time 10 \
|
|
170
|
+
--connect-timeout 5 \
|
|
171
|
+
--request POST \
|
|
172
|
+
--header "Content-Type: application/json" \
|
|
173
|
+
--data "@-" \
|
|
174
|
+
"$WORKER_URL/validate" 2>/dev/null)
|
|
175
|
+
curl_exit=$?
|
|
176
|
+
|
|
177
|
+
if [ $curl_exit -ne 0 ] || [ -z "$response" ]; then
|
|
178
|
+
WORKER_RESULT="network_error"
|
|
179
|
+
return
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# Parse "valid" field from JSON — minimal grep-based parse, no jq dependency
|
|
183
|
+
local valid_field
|
|
184
|
+
valid_field=$(echo "$response" | grep -o '"valid"[[:space:]]*:[[:space:]]*[a-z]*' | head -1 | grep -o '[a-z]*$')
|
|
185
|
+
|
|
186
|
+
if [ "$valid_field" = "true" ]; then
|
|
187
|
+
WORKER_RESULT="valid"
|
|
188
|
+
elif [ "$valid_field" = "false" ]; then
|
|
189
|
+
WORKER_RESULT="invalid"
|
|
190
|
+
else
|
|
191
|
+
# Unexpected response format — treat as network error (fail safe)
|
|
192
|
+
WORKER_RESULT="network_error"
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
131
196
|
LICENSE_VALID=true
|
|
132
197
|
if [ -f "$LICENSE_CACHE" ]; then
|
|
133
198
|
LAST_CHECK=$(cat "$LICENSE_CACHE" 2>/dev/null || echo "0")
|
|
@@ -136,19 +201,41 @@ if [ -f "$LICENSE_CACHE" ]; then
|
|
|
136
201
|
# Cache is fresh, skip validation
|
|
137
202
|
:
|
|
138
203
|
else
|
|
139
|
-
# Re-validate
|
|
140
|
-
|
|
204
|
+
# Re-validate: try Worker first, fall back to local only on network error
|
|
205
|
+
validate_with_worker "$RESOLVED_KEY"
|
|
206
|
+
if [ "$WORKER_RESULT" = "valid" ]; then
|
|
207
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
208
|
+
elif [ "$WORKER_RESULT" = "invalid" ]; then
|
|
209
|
+
# Worker says definitively invalid — no local fallback, clear cache
|
|
210
|
+
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
141
211
|
LICENSE_VALID=false
|
|
142
212
|
else
|
|
143
|
-
|
|
213
|
+
# Network error — fall back to local authorized-keys.txt check
|
|
214
|
+
echo "License server unavailable. Retrying with local validation..." >&2
|
|
215
|
+
if ! "$AGENTS_DIR/install.sh" --check-license-only 2>/dev/null; then
|
|
216
|
+
LICENSE_VALID=false
|
|
217
|
+
else
|
|
218
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
219
|
+
fi
|
|
144
220
|
fi
|
|
145
221
|
fi
|
|
146
222
|
else
|
|
147
|
-
# First check (or cache was invalidated by AK change)
|
|
148
|
-
|
|
223
|
+
# First check (or cache was invalidated by AK change): try Worker first
|
|
224
|
+
validate_with_worker "$RESOLVED_KEY"
|
|
225
|
+
if [ "$WORKER_RESULT" = "valid" ]; then
|
|
226
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
227
|
+
elif [ "$WORKER_RESULT" = "invalid" ]; then
|
|
228
|
+
# Worker says definitively invalid — no local fallback, ensure cache stays clear
|
|
229
|
+
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
149
230
|
LICENSE_VALID=false
|
|
150
231
|
else
|
|
151
|
-
|
|
232
|
+
# Network error — fall back to local authorized-keys.txt check
|
|
233
|
+
echo "License server unavailable. Retrying with local validation..." >&2
|
|
234
|
+
if ! "$AGENTS_DIR/install.sh" --check-license-only 2>/dev/null; then
|
|
235
|
+
LICENSE_VALID=false
|
|
236
|
+
else
|
|
237
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
238
|
+
fi
|
|
152
239
|
fi
|
|
153
240
|
fi
|
|
154
241
|
|
|
@@ -182,12 +269,12 @@ if ! $LICENSE_VALID; then
|
|
|
182
269
|
|
|
183
270
|
# Remove CLAUDE.md managed block
|
|
184
271
|
CLAUDEMD="$PROJECT_DIR/CLAUDE.md"
|
|
185
|
-
if [ -f "$CLAUDEMD" ] && grep -qF "<!-- >>> claude-agents toolkit -->" "$CLAUDEMD" 2>/dev/null; then
|
|
272
|
+
if [ -f "$CLAUDEMD" ] && grep -qF "<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->" "$CLAUDEMD" 2>/dev/null; then
|
|
186
273
|
tmp=$(mktemp)
|
|
187
274
|
in_block=false
|
|
188
275
|
skip_next_blank=false
|
|
189
276
|
while IFS= read -r line; do
|
|
190
|
-
if echo "$line" | grep -qF "<!-- >>> claude-agents toolkit -->"; then
|
|
277
|
+
if echo "$line" | grep -qF "<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->"; then
|
|
191
278
|
in_block=true
|
|
192
279
|
continue
|
|
193
280
|
fi
|
|
@@ -218,8 +305,8 @@ if ! $LICENSE_VALID; then
|
|
|
218
305
|
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
219
306
|
fi
|
|
220
307
|
|
|
221
|
-
echo "
|
|
222
|
-
echo "
|
|
308
|
+
echo "Invalid license key. Toolkit has been disabled for this project."
|
|
309
|
+
echo " Check your key or get one at arthai.dev/pricing"
|
|
223
310
|
exit 0
|
|
224
311
|
fi
|
|
225
312
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
## Engineering Principles (MANDATORY — applies to ALL work)
|
|
2
|
+
|
|
3
|
+
### Research Before Fixing
|
|
4
|
+
- **Never guess.** Before changing code, read the relevant source files, docs, and configs.
|
|
5
|
+
- Understand WHY something is broken before attempting a fix.
|
|
6
|
+
- If your first fix doesn't work, STOP. Don't try another guess. Re-read the code.
|
|
7
|
+
- Use explore-light (Haiku, 1x cost) to scan the codebase before expensive agents investigate.
|
|
8
|
+
|
|
9
|
+
### No Over-Engineering
|
|
10
|
+
- **Do exactly what's needed.** Don't add abstractions, utilities, or frameworks unless the code already uses them.
|
|
11
|
+
- Match existing patterns — run explore-light to find how similar code is structured before writing new code.
|
|
12
|
+
- A bug fix touches the minimum files possible. A feature matches the existing architecture.
|
|
13
|
+
- If you're creating a new class/helper/utility that nothing else in the codebase uses, you're over-engineering.
|
|
14
|
+
|
|
15
|
+
### Test Before Shipping
|
|
16
|
+
- **Run tests locally before pushing.** Never push untested code.
|
|
17
|
+
- If the project has `/precheck`, run it. If it has `/qa`, run it in commit mode.
|
|
18
|
+
- After fixing a bug, verify the fix AND verify nothing else broke (differential testing).
|
|
19
|
+
- If 3+ consecutive fix attempts fail, STOP. Step back and reassess the root cause from scratch.
|
|
20
|
+
|
|
21
|
+
### Deployment Safety
|
|
22
|
+
- **Never modify production systems without explicit confirmation.**
|
|
23
|
+
- Don't change deploy targets, CI pipeline structure, or infrastructure config silently.
|
|
24
|
+
- Don't overwrite existing files during deployment without asking.
|
|
25
|
+
- If a deployment breaks something, investigate before attempting to fix. Don't cascade.
|
|
26
|
+
|
|
27
|
+
## Toolkit Awareness (MANDATORY — READ THIS FIRST)
|
|
28
|
+
|
|
29
|
+
You have a **claude-agents toolkit** installed in this project. It provides specialized
|
|
30
|
+
agents, skills, and hooks that handle domain-specific work better and cheaper.
|
|
31
|
+
|
|
32
|
+
**You are the ORCHESTRATOR.** The triage router fires on every message with a routing
|
|
33
|
+
table and SPEED score. Use it to decide: toolkit or you?
|
|
34
|
+
|
|
35
|
+
### When to use the toolkit (SPEED score 2+):
|
|
36
|
+
- **Multi-step workflows**: `/pr`, `/deploy`, `/planning`, `/implement`, `/qa`, `/ci-fix`
|
|
37
|
+
encode battle-tested sequences you'd otherwise do manually and forget steps
|
|
38
|
+
- **Domain expertise**: SRE, QA, frontend, backend agents have project context baked in
|
|
39
|
+
- **Cost savings**: Haiku/Sonnet agents handle 80% of tasks at 1/60th the cost of Opus
|
|
40
|
+
- **Parallelism**: Team skills spawn multiple agents working simultaneously
|
|
41
|
+
|
|
42
|
+
### When to use YOU directly (SPEED score 0-1):
|
|
43
|
+
- **Quick lookups**: Read/Grep/Glob for finding a file, checking a value, reading code
|
|
44
|
+
- **Small targeted edits**: 1-2 file changes where you already know what to do
|
|
45
|
+
- **Complex reasoning**: Architecture decisions, debugging novel problems, nuanced tradeoffs
|
|
46
|
+
- **Conversation flow**: Follow-up questions, clarifications, explaining code
|
|
47
|
+
- **Creative problem-solving**: When the task doesn't fit any existing pattern
|
|
48
|
+
- **Judgment calls**: Security reviews, design decisions, "should we even do this?"
|
|
49
|
+
|
|
50
|
+
### The balance:
|
|
51
|
+
The toolkit handles **process** (repeatable workflows, domain-specific checks, multi-step
|
|
52
|
+
sequences). You handle **judgment** (reasoning, creativity, novel problems, architecture).
|
|
53
|
+
|
|
54
|
+
A senior engineer doesn't do everything themselves — they delegate routine work and focus
|
|
55
|
+
their expertise where it matters most. That's you. The toolkit is your team.
|
|
56
|
+
|
|
57
|
+
**Don't over-delegate**: If it's faster to just Read a file and answer, do it.
|
|
58
|
+
**Don't under-delegate**: If it's a 5-step workflow the toolkit has a skill for, use it.
|
|
59
|
+
|
|
60
|
+
### Project Knowledge System
|
|
61
|
+
|
|
62
|
+
If this project has been calibrated (`/calibrate`), deep context is available:
|
|
63
|
+
|
|
64
|
+
- **`.claude/project-profile.md`** — Architecture patterns, coding conventions, domain model,
|
|
65
|
+
testing style. Read this before writing any code to match the project's patterns.
|
|
66
|
+
- **`.claude/knowledge/`** — The toolkit's long-term memory for this project:
|
|
67
|
+
- `shared/conventions.md` — Coding rules learned from corrections. **Read before writing code.**
|
|
68
|
+
- `shared/domain.md` — Business rules beyond what's in the code. **Read before domain decisions.**
|
|
69
|
+
- `shared/vocabulary.md` — What the team calls things. **Use these terms.**
|
|
70
|
+
- `shared/patterns.md` — Architecture patterns. **Follow these when adding new code.**
|
|
71
|
+
- `agents/{your-name}.md` — Your past learning. **Read on session start.**
|
|
72
|
+
- **Write back** when you learn something new — corrections, discoveries, decisions.
|
|
73
|
+
- See `knowledge/README.md` for the full protocol.
|
|
74
|
+
- **`.claude/knowledge/external/sources.md`** — Where team knowledge lives outside code
|
|
75
|
+
(Notion, Linear, Figma, etc.). Check before making decisions that might already be documented.
|
|
76
|
+
|
|
77
|
+
## Session Start Behavior (MANDATORY)
|
|
78
|
+
|
|
79
|
+
On your FIRST response in every new session, ALWAYS start with a brief status line
|
|
80
|
+
using context from the SessionStart hook. Include:
|
|
81
|
+
- Current branch + uncommitted file count
|
|
82
|
+
- Docker/infra status (if problems detected)
|
|
83
|
+
- Open PRs or assigned issues (if any)
|
|
84
|
+
- Any red flags (pending migrations, expired tokens)
|
|
85
|
+
|
|
86
|
+
Format: 1-3 compact lines before addressing the user's request. Example:
|
|
87
|
+
```
|
|
88
|
+
📋 project — main | 5 uncommitted | Docker: postgres ✓ redis ✓ | 2 open PRs
|
|
89
|
+
```
|
|
90
|
+
Then proceed with the user's actual request.
|
|
91
|
+
|
|
92
|
+
**CRITICAL — Greetings and vague first messages**: If the user's first message is a
|
|
93
|
+
greeting ("hey", "hi", "hello", "yo", "sup") or vague ("help", "what's up",
|
|
94
|
+
"what should I work on") or ANY message under 5 words with no specific task —
|
|
95
|
+
**ALWAYS use the `/onboard` skill**. Never respond to greetings yourself. The
|
|
96
|
+
bootstrap hook status line is a quick snapshot — `/onboard` gives the real briefing
|
|
97
|
+
with open PRs, issues, priorities, and actionable next steps.
|
|
98
|
+
|
|
99
|
+
## Routing Trace (MANDATORY)
|
|
100
|
+
|
|
101
|
+
On EVERY response, show a compact routing trace so the user understands the decision
|
|
102
|
+
path. Place it at the end of your response in a dimmed block:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
🔀 Routing: [what triage decided] → [agent/skill/tool used] ([cost tier])
|
|
106
|
+
Why: [1-line reason for this routing choice]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
```
|
|
111
|
+
🔀 Routing: backend bug fix → python-backend agent (Sonnet, 10x)
|
|
112
|
+
Why: touches backend/app/services/, needs CLAUDE.md context, SPEED=4
|
|
113
|
+
```
|
|
114
|
+
```
|
|
115
|
+
🔀 Routing: file lookup → Grep (built-in, 0x)
|
|
116
|
+
Why: single-file search, no project context needed, SPEED=0
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Rules:
|
|
120
|
+
- Always show the SPEED score breakdown if score >= 2
|
|
121
|
+
- Show which hook provided the context (triage-router, bootstrap, etc.)
|
|
122
|
+
- If you chose NOT to use the triage router's suggestion, explain why
|
|
123
|
+
- Skip the trace only for simple follow-up messages in an ongoing conversation
|