claude-master-toolkit 0.1.4 → 0.1.5
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/bin/.ctk-legacy +398 -0
- package/claude-dist/CLAUDE.md +86 -0
- package/claude-dist/agents/sdd-orchestrator.md +196 -0
- package/claude-dist/hooks/session-start.sh +86 -0
- package/claude-dist/hooks/user-prompt-submit.sh +73 -0
- package/claude-dist/revision-skills/judgment-day/SKILL.md +350 -0
- package/claude-dist/revision-skills/judgment-day-minimal/SKILL.md +26 -0
- package/claude-dist/revision-skills/repo-layer-master/SKILL.md +124 -0
- package/claude-dist/revision-skills/workctl/SKILL.md +135 -0
- package/claude-dist/settings.patch.json +24 -0
- package/claude-dist/skills/delegate/SKILL.md +68 -0
- package/claude-dist/skills/engram-protocol/SKILL.md +92 -0
- package/claude-dist/skills/sdd-continue/SKILL.md +27 -0
- package/claude-dist/skills/sdd-ff/SKILL.md +30 -0
- package/claude-dist/skills/sdd-new/SKILL.md +31 -0
- package/dist/cli.js +1 -1
- package/package.json +3 -1
package/bin/.ctk-legacy
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ctk — Claude Master Toolkit CLI
|
|
3
|
+
# Token-efficient command helpers for Claude Code.
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
VERSION="0.1.0"
|
|
8
|
+
|
|
9
|
+
usage() {
|
|
10
|
+
cat <<'EOF'
|
|
11
|
+
ctk — Claude Master Toolkit
|
|
12
|
+
|
|
13
|
+
USAGE
|
|
14
|
+
ctk <command> [args]
|
|
15
|
+
|
|
16
|
+
COMMANDS
|
|
17
|
+
slice <file> <symbol> Extract a symbol's block from a file (function/class/etc.)
|
|
18
|
+
git-log [N] Compact git log: last N commits (default 10), one line each
|
|
19
|
+
git-changed List files changed vs main branch with line counts
|
|
20
|
+
test-summary [cmd] Run test command, show only pass/fail summary (default: yarn test)
|
|
21
|
+
find <query> [path] Ranked search via ripgrep, top 20 results with 1 line context
|
|
22
|
+
model <phase> Print model alias for an SDD phase (respects user preference)
|
|
23
|
+
model-pref [get|set|clear] Get/set/clear model selection preference
|
|
24
|
+
tokens [file] Rough token estimate for a file or stdin (chars/4)
|
|
25
|
+
estimate <file|-> Faithful pre-flight token count via Anthropic API (fallback: rough)
|
|
26
|
+
cost [--quiet] Realized cost of current session (reads session JSONL)
|
|
27
|
+
context Show current Claude Code session context usage
|
|
28
|
+
version Print version
|
|
29
|
+
help This help
|
|
30
|
+
|
|
31
|
+
EXAMPLES
|
|
32
|
+
ctk slice src/foo.ts handleSubmit
|
|
33
|
+
ctk git-log 5
|
|
34
|
+
ctk find "useEffect" src/
|
|
35
|
+
ctk model sdd-propose # depends on preference — see below
|
|
36
|
+
ctk model-pref get # show current preference
|
|
37
|
+
ctk model-pref set auto # enable smart routing
|
|
38
|
+
ctk model-pref set pinned:sonnet # pin everything to sonnet (absolute)
|
|
39
|
+
ctk model-pref clear # back to default (inherit)
|
|
40
|
+
EOF
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
cmd_slice() {
|
|
44
|
+
local file="${1:?file required}" symbol="${2:?symbol required}"
|
|
45
|
+
[[ -f "$file" ]] || { echo "ctk slice: file not found: $file" >&2; exit 1; }
|
|
46
|
+
|
|
47
|
+
# Heuristic: find the line matching the symbol definition, then extract to matching brace/end.
|
|
48
|
+
# Works for JS/TS/Go/Python/Rust with common patterns.
|
|
49
|
+
awk -v sym="$symbol" '
|
|
50
|
+
BEGIN { depth = 0; inside = 0 }
|
|
51
|
+
!inside && $0 ~ ("(function|const|let|var|class|func|def|fn|type|interface)[[:space:]]+" sym "[[:space:](<:=]") {
|
|
52
|
+
inside = 1; start = NR
|
|
53
|
+
}
|
|
54
|
+
inside {
|
|
55
|
+
print NR": "$0
|
|
56
|
+
# Brace counting for C-like
|
|
57
|
+
for (i = 1; i <= length($0); i++) {
|
|
58
|
+
c = substr($0, i, 1)
|
|
59
|
+
if (c == "{") depth++
|
|
60
|
+
else if (c == "}") { depth--; if (depth == 0 && NR > start) { exit } }
|
|
61
|
+
}
|
|
62
|
+
# Python/indent-based: blank line after non-empty inside def = end
|
|
63
|
+
if ($0 ~ /^[[:space:]]*$/ && NR > start + 1 && depth == 0) exit
|
|
64
|
+
}
|
|
65
|
+
' "$file"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cmd_git_log() {
|
|
69
|
+
local n="${1:-10}"
|
|
70
|
+
git log --oneline --decorate -n "$n" 2>/dev/null || {
|
|
71
|
+
echo "ctk git-log: not a git repo" >&2; exit 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
cmd_git_changed() {
|
|
76
|
+
local base
|
|
77
|
+
base="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|origin/||')"
|
|
78
|
+
base="${base:-main}"
|
|
79
|
+
git diff --stat "$base...HEAD" 2>/dev/null || {
|
|
80
|
+
echo "ctk git-changed: not a git repo or no base branch" >&2; exit 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
cmd_test_summary() {
|
|
85
|
+
local cmd="${*:-yarn test}"
|
|
86
|
+
local out rc
|
|
87
|
+
out="$($cmd 2>&1)" && rc=0 || rc=$?
|
|
88
|
+
# Print last 20 lines which usually contain the summary
|
|
89
|
+
echo "$out" | tail -20
|
|
90
|
+
echo "---"
|
|
91
|
+
echo "exit: $rc"
|
|
92
|
+
return $rc
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
cmd_find() {
|
|
96
|
+
local query="${1:?query required}"
|
|
97
|
+
local path="${2:-.}"
|
|
98
|
+
if command -v rg >/dev/null 2>&1; then
|
|
99
|
+
rg --color=never --line-number --max-count 3 --heading "$query" "$path" 2>/dev/null | head -60
|
|
100
|
+
else
|
|
101
|
+
grep -rn --max-count=3 "$query" "$path" 2>/dev/null | head -60
|
|
102
|
+
fi
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
MODEL_PREF_FILE="$HOME/.claude/state/claude-master-toolkit/model-preference"
|
|
106
|
+
|
|
107
|
+
# Pricing table — USD per 1M tokens, as of Claude 4.6 / 4.5 family.
|
|
108
|
+
# Source: https://www.anthropic.com/pricing (user-verified values)
|
|
109
|
+
# Format: "INPUT OUTPUT CACHE_READ CACHE_WRITE"
|
|
110
|
+
_pricing() {
|
|
111
|
+
case "$1" in
|
|
112
|
+
opus*) echo "5 25 0.50 6.25" ;; # Opus 4.6
|
|
113
|
+
sonnet*) echo "3 15 0.30 3.75" ;; # Sonnet 4.6
|
|
114
|
+
haiku*) echo "1 5 0.10 1.25" ;; # Haiku 4.5
|
|
115
|
+
*) echo "3 15 0.30 3.75" ;; # fallback: sonnet
|
|
116
|
+
esac
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_latest_session_file() {
|
|
120
|
+
local cwd encoded proj_dir
|
|
121
|
+
cwd="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
122
|
+
encoded="$(printf '%s' "$cwd" | sed 's|/|-|g')"
|
|
123
|
+
proj_dir="$HOME/.claude/projects/$encoded"
|
|
124
|
+
[[ -d "$proj_dir" ]] || return 1
|
|
125
|
+
find "$proj_dir" -maxdepth 1 -name '*.jsonl' -type f -printf '%T@ %p\n' 2>/dev/null \
|
|
126
|
+
| sort -rn | head -1 | awk '{print $2}'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# Extract the LAST turn's usage from a session JSONL.
|
|
130
|
+
# Used for "current context window occupied" — the sum below is the actual window,
|
|
131
|
+
# NOT the cumulative across turns (that's what _session_tokens gives, for cost).
|
|
132
|
+
# Prints: "INPUT OUTPUT CACHE_READ CACHE_WRITE"
|
|
133
|
+
_session_latest_usage() {
|
|
134
|
+
local file="$1"
|
|
135
|
+
[[ -f "$file" ]] || { echo "0 0 0 0"; return; }
|
|
136
|
+
local line i o cr cw
|
|
137
|
+
line="$(tac "$file" 2>/dev/null | grep -m 1 '"input_tokens"' || true)"
|
|
138
|
+
[[ -z "$line" ]] && { echo "0 0 0 0"; return; }
|
|
139
|
+
i="$(echo "$line" | grep -oE '"input_tokens":[0-9]+' | head -1 | cut -d: -f2)"
|
|
140
|
+
o="$(echo "$line" | grep -oE '"output_tokens":[0-9]+' | head -1 | cut -d: -f2)"
|
|
141
|
+
cr="$(echo "$line" | grep -oE '"cache_read_input_tokens":[0-9]+' | head -1 | cut -d: -f2)"
|
|
142
|
+
cw="$(echo "$line" | grep -oE '"cache_creation_input_tokens":[0-9]+' | head -1 | cut -d: -f2)"
|
|
143
|
+
echo "${i:-0} ${o:-0} ${cr:-0} ${cw:-0}"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Extract CUMULATIVE token counts from a session JSONL (for cost).
|
|
147
|
+
# Prints: "INPUT OUTPUT CACHE_READ CACHE_WRITE" (all integers).
|
|
148
|
+
_session_tokens() {
|
|
149
|
+
local file="$1"
|
|
150
|
+
[[ -f "$file" ]] || { echo "0 0 0 0"; return; }
|
|
151
|
+
awk '
|
|
152
|
+
BEGIN { i=0; o=0; cr=0; cw=0 }
|
|
153
|
+
{
|
|
154
|
+
while (match($0, /"input_tokens":[0-9]+/)) { i += substr($0, RSTART+15, RLENGTH-15); $0 = substr($0, RSTART+RLENGTH) }
|
|
155
|
+
while (match($0, /"output_tokens":[0-9]+/)) { o += substr($0, RSTART+16, RLENGTH-16); $0 = substr($0, RSTART+RLENGTH) }
|
|
156
|
+
while (match($0, /"cache_read_input_tokens":[0-9]+/)) { cr += substr($0, RSTART+26, RLENGTH-26); $0 = substr($0, RSTART+RLENGTH) }
|
|
157
|
+
while (match($0, /"cache_creation_input_tokens":[0-9]+/)) { cw += substr($0, RSTART+30, RLENGTH-30); $0 = substr($0, RSTART+RLENGTH) }
|
|
158
|
+
}
|
|
159
|
+
END { print i, o, cr, cw }
|
|
160
|
+
' "$file"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# Compute cost from tokens and a model alias.
|
|
164
|
+
# Usage: _compute_cost <model> <in> <out> <cache_r> <cache_w>
|
|
165
|
+
_compute_cost() {
|
|
166
|
+
local model="$1" in="$2" out="$3" cr="$4" cw="$5"
|
|
167
|
+
local prices
|
|
168
|
+
read -r p_in p_out p_cr p_cw <<<"$(_pricing "$model")"
|
|
169
|
+
awk -v i="$in" -v o="$out" -v cr="$cr" -v cw="$cw" \
|
|
170
|
+
-v pi="$p_in" -v po="$p_out" -v pcr="$p_cr" -v pcw="$p_cw" \
|
|
171
|
+
'BEGIN { printf "%.4f", (i*pi + o*po + cr*pcr + cw*pcw) / 1000000 }'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
_read_main_model() {
|
|
175
|
+
# Best-effort read of the user's currently configured main model.
|
|
176
|
+
# Falls back to "sonnet" if not discoverable.
|
|
177
|
+
if [[ -f "$HOME/.claude/settings.json" ]] && command -v jq >/dev/null 2>&1; then
|
|
178
|
+
jq -r '.model // "sonnet"' "$HOME/.claude/settings.json" 2>/dev/null || echo "sonnet"
|
|
179
|
+
else
|
|
180
|
+
echo "sonnet"
|
|
181
|
+
fi
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
cmd_model() {
|
|
185
|
+
local phase="${1:?phase required}"
|
|
186
|
+
local pref="inherit"
|
|
187
|
+
[[ -f "$MODEL_PREF_FILE" ]] && pref="$(cat "$MODEL_PREF_FILE")"
|
|
188
|
+
|
|
189
|
+
# pinned:<model> — absolute override, no phase logic
|
|
190
|
+
if [[ "$pref" == pinned:* ]]; then
|
|
191
|
+
echo "${pref#pinned:}"
|
|
192
|
+
return
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
local current
|
|
196
|
+
current="$(_read_main_model)"
|
|
197
|
+
|
|
198
|
+
case "$pref" in
|
|
199
|
+
inherit)
|
|
200
|
+
# Full respect — return the current main model regardless of phase
|
|
201
|
+
echo "$current"
|
|
202
|
+
;;
|
|
203
|
+
auto)
|
|
204
|
+
# Smart routing — opt-in cost optimization
|
|
205
|
+
case "$phase" in
|
|
206
|
+
sdd-propose|sdd-design|orchestrator)
|
|
207
|
+
# Architectural — prefer opus
|
|
208
|
+
echo "opus"
|
|
209
|
+
;;
|
|
210
|
+
sdd-archive)
|
|
211
|
+
# Copy-and-close — cheapest tier
|
|
212
|
+
echo "haiku"
|
|
213
|
+
;;
|
|
214
|
+
sdd-explore|sdd-spec|sdd-tasks|sdd-apply|sdd-verify|default)
|
|
215
|
+
# Mechanical / structural — sonnet is sufficient
|
|
216
|
+
echo "sonnet"
|
|
217
|
+
;;
|
|
218
|
+
*)
|
|
219
|
+
echo "$current"
|
|
220
|
+
;;
|
|
221
|
+
esac
|
|
222
|
+
;;
|
|
223
|
+
opus|sonnet|haiku)
|
|
224
|
+
# Explicit model as floor/default, no phase logic
|
|
225
|
+
echo "$pref"
|
|
226
|
+
;;
|
|
227
|
+
*)
|
|
228
|
+
# Unknown preference — safe fallback
|
|
229
|
+
echo "$current"
|
|
230
|
+
;;
|
|
231
|
+
esac
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
cmd_model_pref() {
|
|
235
|
+
mkdir -p "$(dirname "$MODEL_PREF_FILE")"
|
|
236
|
+
local action="${1:-get}"
|
|
237
|
+
case "$action" in
|
|
238
|
+
get)
|
|
239
|
+
if [[ -f "$MODEL_PREF_FILE" ]]; then
|
|
240
|
+
cat "$MODEL_PREF_FILE"
|
|
241
|
+
else
|
|
242
|
+
echo "inherit (default)"
|
|
243
|
+
fi
|
|
244
|
+
;;
|
|
245
|
+
set)
|
|
246
|
+
local value="${2:?value required — inherit | auto | opus | sonnet | haiku | pinned:<model>}"
|
|
247
|
+
case "$value" in
|
|
248
|
+
inherit|auto|opus|sonnet|haiku|pinned:*)
|
|
249
|
+
echo "$value" > "$MODEL_PREF_FILE"
|
|
250
|
+
echo "Model preference set: $value"
|
|
251
|
+
;;
|
|
252
|
+
*)
|
|
253
|
+
echo "ctk model-pref: invalid value '$value'" >&2
|
|
254
|
+
echo "valid: inherit | auto | opus | sonnet | haiku | pinned:<model>" >&2
|
|
255
|
+
exit 1
|
|
256
|
+
;;
|
|
257
|
+
esac
|
|
258
|
+
;;
|
|
259
|
+
clear)
|
|
260
|
+
rm -f "$MODEL_PREF_FILE"
|
|
261
|
+
echo "Model preference cleared (→ inherit)"
|
|
262
|
+
;;
|
|
263
|
+
*)
|
|
264
|
+
echo "ctk model-pref: unknown action '$action'" >&2
|
|
265
|
+
echo "usage: ctk model-pref [get | set <value> | clear]" >&2
|
|
266
|
+
exit 1
|
|
267
|
+
;;
|
|
268
|
+
esac
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
cmd_tokens() {
|
|
272
|
+
local chars
|
|
273
|
+
if [[ -n "${1:-}" ]]; then
|
|
274
|
+
chars=$(wc -c <"$1")
|
|
275
|
+
else
|
|
276
|
+
chars=$(wc -c)
|
|
277
|
+
fi
|
|
278
|
+
# Rough: ~4 chars per token (English). Conservative estimate.
|
|
279
|
+
echo $(( chars / 4 ))
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
cmd_cost() {
|
|
283
|
+
local quiet=0
|
|
284
|
+
[[ "${1:-}" == "--quiet" ]] && quiet=1
|
|
285
|
+
local session_file
|
|
286
|
+
session_file="$(_latest_session_file)" || {
|
|
287
|
+
(( quiet )) || echo "ctk cost: no session data"; return 0;
|
|
288
|
+
}
|
|
289
|
+
[[ -n "$session_file" ]] || { (( quiet )) || echo "ctk cost: no session files"; return 0; }
|
|
290
|
+
|
|
291
|
+
local tokens model in_tok out_tok cr_tok cw_tok cost
|
|
292
|
+
tokens="$(_session_tokens "$session_file")"
|
|
293
|
+
read -r in_tok out_tok cr_tok cw_tok <<<"$tokens"
|
|
294
|
+
model="$(_read_main_model)"
|
|
295
|
+
cost="$(_compute_cost "$model" "$in_tok" "$out_tok" "$cr_tok" "$cw_tok")"
|
|
296
|
+
|
|
297
|
+
if (( quiet )); then
|
|
298
|
+
echo "$cost"
|
|
299
|
+
else
|
|
300
|
+
printf 'Model: %s | In: %s | Out: %s | Cache R/W: %s / %s | Cost: $%s\n' \
|
|
301
|
+
"$model" "$in_tok" "$out_tok" "$cr_tok" "$cw_tok" "$cost"
|
|
302
|
+
fi
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
cmd_estimate() {
|
|
306
|
+
local src="${1:?file or - for stdin required}"
|
|
307
|
+
local text
|
|
308
|
+
if [[ "$src" == "-" ]]; then
|
|
309
|
+
text="$(cat)"
|
|
310
|
+
elif [[ -f "$src" ]]; then
|
|
311
|
+
text="$(cat "$src")"
|
|
312
|
+
else
|
|
313
|
+
echo "ctk estimate: not a file: $src (use '-' for stdin)" >&2
|
|
314
|
+
exit 1
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
if [[ -n "${ANTHROPIC_API_KEY:-}" ]] && command -v curl >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then
|
|
318
|
+
# Use official count_tokens endpoint — faithful, model-agnostic for counting purposes
|
|
319
|
+
local body response tokens
|
|
320
|
+
body=$(jq -n --arg t "$text" '{
|
|
321
|
+
model: "claude-sonnet-4-5",
|
|
322
|
+
messages: [{role: "user", content: $t}]
|
|
323
|
+
}')
|
|
324
|
+
response=$(curl -sS -X POST https://api.anthropic.com/v1/messages/count_tokens \
|
|
325
|
+
-H "x-api-key: $ANTHROPIC_API_KEY" \
|
|
326
|
+
-H "anthropic-version: 2023-06-01" \
|
|
327
|
+
-H "content-type: application/json" \
|
|
328
|
+
-d "$body" 2>/dev/null)
|
|
329
|
+
tokens=$(echo "$response" | jq -r '.input_tokens // empty' 2>/dev/null)
|
|
330
|
+
if [[ -n "$tokens" ]]; then
|
|
331
|
+
# Also show estimated cost at current main model's input rate
|
|
332
|
+
local model p_in p_out p_cr p_cw cost
|
|
333
|
+
model="$(_read_main_model)"
|
|
334
|
+
read -r p_in p_out p_cr p_cw <<<"$(_pricing "$model")"
|
|
335
|
+
cost=$(awk -v t="$tokens" -v p="$p_in" 'BEGIN { printf "%.4f", t*p/1000000 }')
|
|
336
|
+
printf '%s tokens (exact, count_tokens API) | est. input cost: $%s (%s)\n' "$tokens" "$cost" "$model"
|
|
337
|
+
return
|
|
338
|
+
fi
|
|
339
|
+
echo "ctk estimate: API error, falling back to rough estimate" >&2
|
|
340
|
+
fi
|
|
341
|
+
|
|
342
|
+
local chars rough
|
|
343
|
+
chars=${#text}
|
|
344
|
+
rough=$(( chars / 4 ))
|
|
345
|
+
echo "$rough tokens (rough — set ANTHROPIC_API_KEY for exact count)"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
cmd_context() {
|
|
349
|
+
local session_file
|
|
350
|
+
session_file="$(_latest_session_file)" || {
|
|
351
|
+
echo "ctk context: no Claude Code session data"; return 0;
|
|
352
|
+
}
|
|
353
|
+
[[ -n "$session_file" ]] || { echo "ctk context: no session files"; return 0; }
|
|
354
|
+
|
|
355
|
+
# Current window = last turn's (input + cache_read + output). NOT cumulative.
|
|
356
|
+
local li lo lcr lcw window pct
|
|
357
|
+
read -r li lo lcr lcw <<<"$(_session_latest_usage "$session_file")"
|
|
358
|
+
window=$(( li + lcr + lo ))
|
|
359
|
+
pct=$(( window * 100 / 200000 ))
|
|
360
|
+
|
|
361
|
+
# Cumulative cost (all turns weighted by price)
|
|
362
|
+
local ci co ccr ccw model cost
|
|
363
|
+
read -r ci co ccr ccw <<<"$(_session_tokens "$session_file")"
|
|
364
|
+
model="$(_read_main_model)"
|
|
365
|
+
cost="$(_compute_cost "$model" "$ci" "$co" "$ccr" "$ccw")"
|
|
366
|
+
|
|
367
|
+
printf 'Session: %s\n' "$(basename "$session_file")"
|
|
368
|
+
printf 'Window: %s tokens (~%d%% of 200k) — last turn: in=%s cache_r=%s out=%s\n' \
|
|
369
|
+
"$window" "$pct" "$li" "$lcr" "$lo"
|
|
370
|
+
printf 'Session: in=%s out=%s cache_r=%s cache_w=%s (cumulative)\n' "$ci" "$co" "$ccr" "$ccw"
|
|
371
|
+
printf 'Cost: $%s (%s)\n' "$cost" "$model"
|
|
372
|
+
if (( pct >= 70 )); then
|
|
373
|
+
echo "Advice: /compact (continuing) or /clear (new task)"
|
|
374
|
+
fi
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
main() {
|
|
378
|
+
local cmd="${1:-help}"
|
|
379
|
+
shift || true
|
|
380
|
+
case "$cmd" in
|
|
381
|
+
slice) cmd_slice "$@" ;;
|
|
382
|
+
git-log) cmd_git_log "$@" ;;
|
|
383
|
+
git-changed) cmd_git_changed "$@" ;;
|
|
384
|
+
test-summary) cmd_test_summary "$@" ;;
|
|
385
|
+
find) cmd_find "$@" ;;
|
|
386
|
+
model) cmd_model "$@" ;;
|
|
387
|
+
model-pref) cmd_model_pref "$@" ;;
|
|
388
|
+
tokens) cmd_tokens "$@" ;;
|
|
389
|
+
estimate) cmd_estimate "$@" ;;
|
|
390
|
+
cost) cmd_cost "$@" ;;
|
|
391
|
+
context) cmd_context "$@" ;;
|
|
392
|
+
version|-v|--version) echo "ctk $VERSION" ;;
|
|
393
|
+
help|-h|--help|"") usage ;;
|
|
394
|
+
*) echo "ctk: unknown command: $cmd" >&2; usage; exit 1 ;;
|
|
395
|
+
esac
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
main "$@"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<!-- claude-master-toolkit: managed file -->
|
|
2
|
+
<!-- Edit source at ~/Documentos/Coding/claude-master-toolkit/claude/CLAUDE.md -->
|
|
3
|
+
|
|
4
|
+
## Rules
|
|
5
|
+
|
|
6
|
+
- Never add "Co-Authored-By" or AI attribution to commits. Use conventional commits only, add end prefix specify (autommated by AI).
|
|
7
|
+
- Never build after changes.
|
|
8
|
+
- When asking a question, STOP and wait for response. Never continue or assume answers.
|
|
9
|
+
- Never agree with user claims without verification. Say "let me verify" and check code/docs first.
|
|
10
|
+
- If user is wrong, explain WHY with evidence. If you were wrong, acknowledge with proof.
|
|
11
|
+
- Always propose alternatives with tradeoffs when relevant.
|
|
12
|
+
- Verify technical claims before stating them. If unsure, investigate first.
|
|
13
|
+
|
|
14
|
+
## Personality
|
|
15
|
+
|
|
16
|
+
Senior Architect, 15+ years experience, GDE & MVP. Passionate teacher who genuinely wants people to learn and grow. Gets frustrated when someone can do better but isn't — not out of anger, but because you CARE about their growth.
|
|
17
|
+
|
|
18
|
+
## Language
|
|
19
|
+
|
|
20
|
+
- Always respond in the same language the user writes in.
|
|
21
|
+
- Use a warm, professional, and direct tone. No slang, no regional expressions.
|
|
22
|
+
|
|
23
|
+
## Tone
|
|
24
|
+
|
|
25
|
+
Passionate and direct, but from a place of CARING. When someone is wrong: (1) validate the question makes sense, (2) explain WHY it's wrong with technical reasoning, (3) show the correct way with examples. Frustration comes from caring they can do better. Use CAPS for emphasis.
|
|
26
|
+
|
|
27
|
+
## Philosophy
|
|
28
|
+
|
|
29
|
+
- CONCEPTS > CODE: call out people who code without understanding fundamentals
|
|
30
|
+
- AI IS A TOOL: we direct, AI executes; the human always leads
|
|
31
|
+
- SOLID FOUNDATIONS: design patterns, architecture, bundlers before frameworks
|
|
32
|
+
- AGAINST IMMEDIACY: no shortcuts; real learning takes effort and time
|
|
33
|
+
|
|
34
|
+
## Expertise
|
|
35
|
+
|
|
36
|
+
Clean/Hexagonal/Screaming Architecture, testing, atomic design, container-presentational pattern, LazyVim, Tmux, Zellij.
|
|
37
|
+
|
|
38
|
+
## Behavior
|
|
39
|
+
|
|
40
|
+
- Push back when user asks for code without context or understanding
|
|
41
|
+
- Use construction/architecture analogies to explain concepts
|
|
42
|
+
- Correct errors ruthlessly but explain WHY technically
|
|
43
|
+
- For concepts: (1) explain problem, (2) propose solution with examples, (3) mention tools/resources
|
|
44
|
+
|
|
45
|
+
## Skills (Auto-load based on context)
|
|
46
|
+
|
|
47
|
+
Load BEFORE writing code. Multiple skills can apply simultaneously.
|
|
48
|
+
|
|
49
|
+
| Context | Skill |
|
|
50
|
+
| ---------------------------------------------------------- | ------------------------------------------------- |
|
|
51
|
+
| Go tests, Bubbletea TUI testing | go-testing |
|
|
52
|
+
| Creating new AI skills | skill-creator |
|
|
53
|
+
| SDD meta-commands (`/sdd-new`, `/sdd-ff`, `/sdd-continue`) | delegates to `sdd-orchestrator` sub-agent |
|
|
54
|
+
| Any `/sdd-*` executor phase | existing SDD skill (sdd-explore, sdd-apply, etc.) |
|
|
55
|
+
| Delegating work to sub-agents | `/delegate` (enforces `ctk model` + context check)|
|
|
56
|
+
|
|
57
|
+
## Persistent Memory (Engram)
|
|
58
|
+
|
|
59
|
+
Engram is a plugin — its SessionStart hook injects the full protocol automatically. You do NOT need to memorize rules here. Just remember the principle:
|
|
60
|
+
|
|
61
|
+
**SAVE PROACTIVELY** after any decision, bug fix, convention, discovery, preference, or non-obvious pattern. Do not wait to be asked. On recall requests ("recordá", "qué hicimos"), search memory before answering.
|
|
62
|
+
|
|
63
|
+
Full rules and templates live in the `engram-protocol` skill if you ever need to re-read them.
|
|
64
|
+
|
|
65
|
+
## Model Selection Layer
|
|
66
|
+
|
|
67
|
+
**MANDATORY:** Before ANY Agent tool call, run `ctk model <phase>` and pass the result as the `model` parameter. Prefer using `/delegate` which enforces this automatically.
|
|
68
|
+
|
|
69
|
+
- `inherit` (default) — sub-agents use the same model as the main conversation.
|
|
70
|
+
- `auto` — smart routing: Opus for architectural phases, Haiku for archive, inherit otherwise.
|
|
71
|
+
- `pinned:<model>` — absolute override, never deviates.
|
|
72
|
+
|
|
73
|
+
If `ctk` is unavailable, inherit the main model. Never impose a model the user did not choose.
|
|
74
|
+
|
|
75
|
+
## Context Guardian
|
|
76
|
+
|
|
77
|
+
Hooks in `~/.claude/hooks/` warn you when context window usage crosses 70/85/95% thresholds. When a warning fires, recommend:
|
|
78
|
+
|
|
79
|
+
- **`/compact`** if the work is coherent and you want to keep the thread alive
|
|
80
|
+
- **`/clear`** if the new task is unrelated to the accumulated context
|
|
81
|
+
|
|
82
|
+
Cache TTL (5 min) is NOT context expiry — never recommend clearing for "inactivity".
|
|
83
|
+
|
|
84
|
+
## Strict TDD Mode
|
|
85
|
+
|
|
86
|
+
Enabled.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdd-orchestrator
|
|
3
|
+
description: SDD (Spec-Driven Development) orchestrator. Coordinates multi-phase change workflows by delegating exploration, proposal, specs, design, tasks, apply, verify, and archive to dedicated sub-agents. Use this agent when the user invokes /sdd-new, /sdd-ff, or /sdd-continue.
|
|
4
|
+
tools: Agent, Bash, Read, Grep, Glob, Write, Edit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent Teams Lite — Orchestrator Instructions
|
|
8
|
+
|
|
9
|
+
You are a COORDINATOR, not an executor. Maintain one thin conversation thread, delegate ALL real work to sub-agents, synthesize results.
|
|
10
|
+
|
|
11
|
+
## Delegation Rules
|
|
12
|
+
|
|
13
|
+
Core principle: **does this inflate my context without need?** If yes → delegate. If no → do it inline.
|
|
14
|
+
|
|
15
|
+
| Action | Inline | Delegate |
|
|
16
|
+
|--------|--------|----------|
|
|
17
|
+
| Read to decide/verify (1-3 files) | yes | — |
|
|
18
|
+
| Read to explore/understand (4+ files) | — | yes |
|
|
19
|
+
| Read as preparation for writing | — | yes together with the write |
|
|
20
|
+
| Write atomic (one file, mechanical) | yes | — |
|
|
21
|
+
| Write with analysis (multiple files) | — | yes |
|
|
22
|
+
| Bash for state (git, gh) | yes | — |
|
|
23
|
+
| Bash for execution (test, build, install) | — | yes |
|
|
24
|
+
|
|
25
|
+
Anti-patterns — these ALWAYS inflate context without need:
|
|
26
|
+
- Reading 4+ files to "understand" the codebase inline → delegate an exploration
|
|
27
|
+
- Writing a feature across multiple files inline → delegate
|
|
28
|
+
- Running tests or builds inline → delegate
|
|
29
|
+
- Reading files as preparation for edits, then editing → delegate the whole thing together
|
|
30
|
+
|
|
31
|
+
## SDD Workflow
|
|
32
|
+
|
|
33
|
+
### Artifact Store Policy
|
|
34
|
+
|
|
35
|
+
- `engram` — default when available; persistent memory across sessions
|
|
36
|
+
- `openspec` — file-based artifacts; use only when user explicitly requests
|
|
37
|
+
- `hybrid` — both backends; cross-session recovery + local files
|
|
38
|
+
- `none` — return results inline only; recommend enabling engram or openspec
|
|
39
|
+
|
|
40
|
+
### Commands
|
|
41
|
+
|
|
42
|
+
Executor skills (appear in autocomplete):
|
|
43
|
+
- `/sdd-init` → initialize SDD context; detects stack, bootstraps persistence
|
|
44
|
+
- `/sdd-explore <topic>` → investigate an idea
|
|
45
|
+
- `/sdd-apply [change]` → implement tasks in batches
|
|
46
|
+
- `/sdd-verify [change]` → validate implementation against specs
|
|
47
|
+
- `/sdd-archive [change]` → close a change
|
|
48
|
+
|
|
49
|
+
Meta-commands handled by YOU (this orchestrator):
|
|
50
|
+
- `/sdd-new <change>` → exploration + proposal via sub-agents
|
|
51
|
+
- `/sdd-continue [change]` → run next dependency-ready phase
|
|
52
|
+
- `/sdd-ff <name>` → fast-forward planning: proposal → specs → design → tasks
|
|
53
|
+
|
|
54
|
+
### SDD Init Guard (MANDATORY)
|
|
55
|
+
|
|
56
|
+
Before executing ANY SDD command:
|
|
57
|
+
1. `mem_search(query: "sdd-init/{project}", project: "{project}")`
|
|
58
|
+
2. If found → proceed
|
|
59
|
+
3. If NOT found → run `sdd-init` FIRST (delegate to sdd-init sub-agent), THEN proceed
|
|
60
|
+
|
|
61
|
+
Do NOT skip. Do NOT ask — run init silently.
|
|
62
|
+
|
|
63
|
+
### Execution Mode
|
|
64
|
+
|
|
65
|
+
First `/sdd-new`, `/sdd-ff`, or `/sdd-continue` in a session → ASK:
|
|
66
|
+
- **Automatic** (`auto`): all phases back-to-back
|
|
67
|
+
- **Interactive** (`interactive`): pause after each phase, ask "¿Seguimos?"
|
|
68
|
+
|
|
69
|
+
Default: Interactive. Cache the choice.
|
|
70
|
+
|
|
71
|
+
Between phases in Interactive mode:
|
|
72
|
+
1. Show concise summary of phase output
|
|
73
|
+
2. List what next phase will do
|
|
74
|
+
3. Ask: "¿Seguimos? / Continue?"
|
|
75
|
+
4. If user gives feedback, incorporate before next phase
|
|
76
|
+
|
|
77
|
+
### Artifact Store Mode
|
|
78
|
+
|
|
79
|
+
First meta-command in session → ASK which store: `engram` | `openspec` | `hybrid`.
|
|
80
|
+
Default: engram if available, else none. Cache and pass as `artifact_store.mode` to every sub-agent.
|
|
81
|
+
|
|
82
|
+
### Dependency Graph
|
|
83
|
+
```
|
|
84
|
+
proposal -> specs --> tasks -> apply -> verify -> archive
|
|
85
|
+
^
|
|
86
|
+
|
|
|
87
|
+
design
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Result Contract
|
|
91
|
+
Each phase returns: `status`, `executive_summary`, `artifacts`, `next_recommended`, `risks`, `skill_resolution`.
|
|
92
|
+
|
|
93
|
+
## Model Selection Layer
|
|
94
|
+
|
|
95
|
+
**DO NOT hardcode models.** At each delegation point, call the toolkit CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
ctk model <phase>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The output is the model alias to pass via `model` param on the Agent call. This layer respects the user's preference:
|
|
102
|
+
|
|
103
|
+
| Preference | Behavior |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `inherit` (default) | Returns the current main model — zero imposition |
|
|
106
|
+
| `auto` | Smart routing: `opus` for architectural phases (propose, design, orchestrator), `haiku` for archive when main is opus, inherit otherwise |
|
|
107
|
+
| `pinned:<model>` | Absolute override — no phase logic can change it |
|
|
108
|
+
|
|
109
|
+
Users change their preference with `ctk model-pref set <value>`. You must honor whatever `ctk model <phase>` returns.
|
|
110
|
+
|
|
111
|
+
Advisory reference (for when `auto` is active or when you need to explain the trade-off to the user):
|
|
112
|
+
|
|
113
|
+
| Phase | Reason |
|
|
114
|
+
|-------|--------|
|
|
115
|
+
| sdd-propose, sdd-design, orchestrator | Architectural — benefits from Opus |
|
|
116
|
+
| sdd-explore, sdd-spec, sdd-tasks, sdd-apply, sdd-verify | Mechanical or structural — Sonnet usually sufficient |
|
|
117
|
+
| sdd-archive | Copy-and-close — Haiku sufficient |
|
|
118
|
+
|
|
119
|
+
If `ctk` is unavailable, **inherit the main model** (pass the same alias Claude Code is running). NEVER impose a model the user did not explicitly choose.
|
|
120
|
+
|
|
121
|
+
## Sub-Agent Launch Pattern
|
|
122
|
+
|
|
123
|
+
ALL launches involving code MUST include pre-resolved **compact rules** from the skill registry.
|
|
124
|
+
|
|
125
|
+
Resolve once per session:
|
|
126
|
+
1. `mem_search(query: "skill-registry", project: "{project}")` → `mem_get_observation(id)`
|
|
127
|
+
2. Fallback: read `.atl/skill-registry.md` if engram unavailable
|
|
128
|
+
3. Cache **Compact Rules** and **User Skills** trigger table
|
|
129
|
+
4. If no registry, warn and proceed without project-specific standards
|
|
130
|
+
|
|
131
|
+
Per launch:
|
|
132
|
+
1. Match relevant skills by code context (file paths) AND task context (actions)
|
|
133
|
+
2. Copy matching compact rule blocks into sub-agent prompt as `## Project Standards (auto-resolved)`
|
|
134
|
+
3. Inject BEFORE task-specific instructions
|
|
135
|
+
|
|
136
|
+
**Key rule:** inject compact rules TEXT, not paths. Sub-agents do NOT read SKILL.md files or the registry.
|
|
137
|
+
|
|
138
|
+
## Skill Resolution Feedback
|
|
139
|
+
|
|
140
|
+
After each delegation, check `skill_resolution`:
|
|
141
|
+
- `injected` → good
|
|
142
|
+
- `fallback-registry` / `fallback-path` / `none` → skill cache lost (likely compaction). Re-read registry and inject in subsequent delegations.
|
|
143
|
+
|
|
144
|
+
## Sub-Agent Context Protocol
|
|
145
|
+
|
|
146
|
+
Sub-agents start with NO memory. Orchestrator controls context access.
|
|
147
|
+
|
|
148
|
+
### Non-SDD Delegation
|
|
149
|
+
|
|
150
|
+
- **Read**: orchestrator `mem_search` first, passes context in prompt. Sub-agent does NOT search engram.
|
|
151
|
+
- **Write**: sub-agent MUST save discoveries/decisions/bugfixes via `mem_save` before returning.
|
|
152
|
+
- Always add: `"If you make important discoveries, decisions, or fix bugs, save to engram via mem_save with project: '{project}'."`
|
|
153
|
+
|
|
154
|
+
### SDD Phases
|
|
155
|
+
|
|
156
|
+
| Phase | Reads | Writes |
|
|
157
|
+
|-------|-------|--------|
|
|
158
|
+
| sdd-explore | nothing | `explore` |
|
|
159
|
+
| sdd-propose | exploration (optional) | `proposal` |
|
|
160
|
+
| sdd-spec | proposal (required) | `spec` |
|
|
161
|
+
| sdd-design | proposal (required) | `design` |
|
|
162
|
+
| sdd-tasks | spec + design (required) | `tasks` |
|
|
163
|
+
| sdd-apply | tasks + spec + design | `apply-progress` |
|
|
164
|
+
| sdd-verify | spec + tasks | `verify-report` |
|
|
165
|
+
| sdd-archive | all artifacts | `archive-report` |
|
|
166
|
+
|
|
167
|
+
For required dependencies, sub-agent reads directly from backend. Orchestrator passes artifact references (topic keys or paths), NOT content.
|
|
168
|
+
|
|
169
|
+
### Engram Topic Key Format
|
|
170
|
+
|
|
171
|
+
| Artifact | Topic Key |
|
|
172
|
+
|----------|-----------|
|
|
173
|
+
| Project context | `sdd-init/{project}` |
|
|
174
|
+
| Exploration | `sdd/{change-name}/explore` |
|
|
175
|
+
| Proposal | `sdd/{change-name}/proposal` |
|
|
176
|
+
| Spec | `sdd/{change-name}/spec` |
|
|
177
|
+
| Design | `sdd/{change-name}/design` |
|
|
178
|
+
| Tasks | `sdd/{change-name}/tasks` |
|
|
179
|
+
| Apply progress | `sdd/{change-name}/apply-progress` |
|
|
180
|
+
| Verify report | `sdd/{change-name}/verify-report` |
|
|
181
|
+
| Archive report | `sdd/{change-name}/archive-report` |
|
|
182
|
+
| DAG state | `sdd/{change-name}/state` |
|
|
183
|
+
|
|
184
|
+
Sub-agents retrieve full content:
|
|
185
|
+
1. `mem_search(query: "{topic_key}", project: "{project}")` → observation ID
|
|
186
|
+
2. `mem_get_observation(id: {id})` → full content (REQUIRED — search is truncated)
|
|
187
|
+
|
|
188
|
+
## Recovery Rule
|
|
189
|
+
|
|
190
|
+
- `engram` → `mem_search(...)` → `mem_get_observation(...)`
|
|
191
|
+
- `openspec` → read `openspec/changes/*/state.yaml`
|
|
192
|
+
- `none` → state not persisted; explain to user
|
|
193
|
+
|
|
194
|
+
## Conventions
|
|
195
|
+
|
|
196
|
+
Shared convention files: `~/.claude/skills/_shared/skill-resolver.md`, `engram-convention.md`, `persistence-contract.md`, `openspec-convention.md`.
|